From d55213e1aa1bf5d934afaef3f28d4b5c7a5cc7f9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 12:39:44 +0200 Subject: Add initial batchCancelAsync implementation --- src/contract_wrappers/exchange_wrapper.ts | 45 +++++++++++++++++++++++++++++++ src/types.ts | 6 +++++ 2 files changed, 51 insertions(+) diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 408d3deed..1a675ee8e 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -227,6 +227,51 @@ export class ExchangeWrapper extends ContractWrapper { ); this.throwErrorLogsAsErrors(response.logs); } + /** + * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction. + */ + public async batchCancelOrderAsync( + orders: Array, takerTokenCancelAmounts: BigNumber.BigNumber[]): Promise { + const makers = _.map(orders, order => order.maker); + assert.isSameLength('orders', orders, 'takerTokenCancelAmounts', takerTokenCancelAmounts); + assert.assert(_.isEmpty(orders), '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(orders, takerTokenCancelAmounts); + _.forEach(ordersAndTakerTokenCancelAmounts, + async ([order, takerTokenCancelAmount]: [Order|SignedOrder, BigNumber.BigNumber]) => { + 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); + }); + const exchangeInstance = await this.getExchangeContractAsync(); + const orderAddressesAndValues = _.map(orders, order => { + return ExchangeWrapper.getOrderAddressesAndValues(order); + }); + // _.unzip doesn't type check if values have different types :'( + const [orderAddresses, orderValues] = _.unzip(orderAddressesAndValues); + const gas = await exchangeInstance.batchCancel.estimateGas( + orderAddresses, + orderValues, + takerTokenCancelAmounts, + { + from: maker, + }, + ); + const response: ContractResponse = await exchangeInstance.batchCancel( + orderAddresses, + orderValues, + takerTokenCancelAmounts, + { + from: maker, + gas, + }, + ); + this.throwErrorLogsAsErrors(response.logs); + } /** * Subscribe to an event type emitted by the Exchange smart contract */ diff --git a/src/types.ts b/src/types.ts index 877864f49..a1bd6d19e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -80,6 +80,12 @@ export interface ExchangeContract extends ContractInstance { estimateGas: (orderAddresses: OrderAddresses, orderValues: OrderValues, cancelAmount: BigNumber.BigNumber, txOpts?: TxOpts) => number; }; + batchCancel: { + (orderAddresses: OrderAddresses[], orderValues: OrderValues[], cancelAmount: BigNumber.BigNumber[], + txOpts?: TxOpts): ContractResponse; + estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], cancelAmount: BigNumber.BigNumber[], + txOpts?: TxOpts) => number; + }; filled: { call: (orderHash: string) => BigNumber.BigNumber; }; -- cgit