diff options
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 36 | ||||
-rw-r--r-- | src/types.ts | 5 | ||||
-rw-r--r-- | test/exchange_wrapper_test.ts | 34 |
3 files changed, 46 insertions, 29 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 1ae5b260b..326f0e812 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -18,7 +18,7 @@ import { CreateContractEvent, ContractEventObj, EventCallback, - ContractResponse, + ContractResponse, OrderCancellationRequest, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -232,29 +232,31 @@ export class ExchangeWrapper extends ContractWrapper { /** * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction. */ - public async batchCancelOrderAsync( - orders: Array<Order|SignedOrder>, takerTokenCancelAmounts: BigNumber.BigNumber[]): Promise<void> { - const makers = _.map(orders, order => order.maker); - assert.isSameLength('orders', orders, 'takerTokenCancelAmounts', takerTokenCancelAmounts); - assert.assert(!_.isEmpty(orders), 'Can not cancel an empty batch'); + public async batchCancelOrderAsync(cancellationRequestsBatch: OrderCancellationRequest[]): Promise<void> { + const makers = _.map(cancellationRequestsBatch, cancellationRequest => cancellationRequest.order.maker); + assert.assert(!_.isEmpty(cancellationRequestsBatch), 'Can not cancel an empty batch'); assert.assert(_.uniq(makers).length === 1, 'Can not cancel orders from multiple makers in a single batch'); const maker = makers[0]; - // _.zip doesn't type check if values have different types :'( - const ordersAndTakerTokenCancelAmounts = _.zip<any>(orders, takerTokenCancelAmounts); - _.forEach(ordersAndTakerTokenCancelAmounts, - async ([order, takerTokenCancelAmount]: [Order|SignedOrder, BigNumber.BigNumber]) => { + _.forEach(cancellationRequestsBatch, + async (cancellationRequest: OrderCancellationRequest) => { assert.doesConformToSchema('order', - SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), orderSchema); - assert.isBigNumber('takerTokenCancelAmount', takerTokenCancelAmount); - await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'order.maker', order.maker); - await this.validateCancelOrderAndThrowIfInvalidAsync(order, takerTokenCancelAmount); + SchemaValidator.convertToJSONSchemaCompatibleObject(cancellationRequest.order as object), orderSchema); + assert.isBigNumber('takerTokenCancelAmount', cancellationRequest.takerTokenCancelAmount); + await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'order.maker', + cancellationRequest.order.maker); + await this.validateCancelOrderAndThrowIfInvalidAsync( + cancellationRequest.order, cancellationRequest.takerTokenCancelAmount); }); const exchangeInstance = await this.getExchangeContractAsync(); - const orderAddressesAndValues = _.map(orders, order => { - return ExchangeWrapper.getOrderAddressesAndValues(order); + const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(cancellationRequestsBatch, cancellationRequest => { + return [ + ...ExchangeWrapper.getOrderAddressesAndValues(cancellationRequest.order), + cancellationRequest.takerTokenCancelAmount, + ]; }); // _.unzip doesn't type check if values have different types :'( - const [orderAddresses, orderValues] = _.unzip<any>(orderAddressesAndValues); + const [orderAddresses, orderValues, takerTokenCancelAmounts] = + _.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts); const gas = await exchangeInstance.batchCancel.estimateGas( orderAddresses, orderValues, diff --git a/src/types.ts b/src/types.ts index a1bd6d19e..84f16b9b9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -228,3 +228,8 @@ export interface SubscriptionOpts { } export type DoneCallback = (err?: Error) => void; + +export interface OrderCancellationRequest { + order: Order|SignedOrder; + takerTokenCancelAmount: BigNumber.BigNumber; +} diff --git a/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index 43f8683c8..683c4b17d 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -16,7 +16,7 @@ import { ExchangeEvents, ContractEvent, DoneCallback, - ExchangeContractErrs, + ExchangeContractErrs, OrderCancellationRequest, } from '../src/types'; import {FillScenarios} from './utils/fill_scenarios'; import {TokenUtils} from './utils/token_utils'; @@ -120,7 +120,7 @@ describe('ExchangeWrapper', () => { expect(isValid).to.be.true(); }); }); - describe('fill order', () => { + describe('fill order(s)', () => { let makerTokenAddress: string; let takerTokenAddress: string; let coinbase: string; @@ -392,34 +392,44 @@ describe('ExchangeWrapper', () => { describe('#batchCancelOrderAsync', () => { let anotherSignedOrder: SignedOrder; let anotherOrderHashHex: string; + let cancelBatch: OrderCancellationRequest[]; beforeEach(async () => { anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); anotherOrderHashHex = await zeroEx.getOrderHashHexAsync(anotherSignedOrder); + cancelBatch = [ + { + order: signedOrder, + takerTokenCancelAmount: cancelAmount, + }, + { + order: anotherSignedOrder, + takerTokenCancelAmount: cancelAmount, + }, + ]; }); describe('failed batch cancels', () => { - it('should throw when length of orders and cancelAmounts mismatch', async () => { - return expect(zeroEx.exchange.batchCancelOrderAsync([signedOrder], [])) - .to.be.rejectedWith('orders and takerTokenCancelAmounts length mismatch. 1 != 0'); - }); it('should throw when orders are empty', async () => { - return expect(zeroEx.exchange.batchCancelOrderAsync([], [])) + return expect(zeroEx.exchange.batchCancelOrderAsync([])) .to.be.rejectedWith('Can not cancel an empty batch'); }); it.only('should throw when orders have different makers', async () => { const signedOrderWithADifferentMaker = await fillScenarios.createFillableSignedOrderAsync( makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount, ); - return expect(zeroEx.exchange.batchCancelOrderAsync( - [signedOrder, signedOrderWithADifferentMaker], [cancelAmount, cancelAmount])) - .to.be.rejectedWith('Can not cancel orders from multiple makers in a single batch'); + return expect(zeroEx.exchange.batchCancelOrderAsync([ + cancelBatch[0], + { + order: signedOrderWithADifferentMaker, + takerTokenCancelAmount: cancelAmount, + }, + ])).to.be.rejectedWith('Can not cancel orders from multiple makers in a single batch'); }); }); describe('successful batch cancels', () => { it('should cancel a batch of orders', async () => { - await zeroEx.exchange.batchCancelOrderAsync( - [signedOrder, anotherSignedOrder], [cancelAmount, cancelAmount]); + await zeroEx.exchange.batchCancelOrderAsync(cancelBatch); const cancelledAmount = await zeroEx.exchange.getCanceledTakerAmountAsync(orderHashHex); const anotherCancelledAmount = await zeroEx.exchange.getCanceledTakerAmountAsync( anotherOrderHashHex); |