diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 60 | ||||
-rw-r--r-- | src/types.ts | 12 |
2 files changed, 55 insertions, 17 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 4f132656e..47c49fad6 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -19,6 +19,7 @@ import { ContractEventObj, EventCallback, ContractResponse, + OrderCancellationRequest, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -226,32 +227,57 @@ export class ExchangeWrapper extends ContractWrapper { /** * Cancel a given fill amount of an order. Cancellations are cumulative. */ - public async cancelOrderAsync(order: Order|SignedOrder, takerTokenCancelAmount: BigNumber.BigNumber): - Promise<void> { - assert.doesConformToSchema('order', - SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), - orderSchema); - assert.isBigNumber('takerTokenCancelAmount', takerTokenCancelAmount); - await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'order.maker', order.maker); - + public async cancelOrderAsync( + order: Order|SignedOrder, takerTokenCancelAmount: BigNumber.BigNumber): Promise<void> { + await this.batchCancelOrderAsync([{ + order, + takerTokenCancelAmount, + }]); + } + /** + * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction. + */ + public async batchCancelOrderAsync(cancellationRequestsBatch: OrderCancellationRequest[]): Promise<void> { + const makers = _.map(cancellationRequestsBatch, cancellationRequest => cancellationRequest.order.maker); + if (_.isEmpty(cancellationRequestsBatch)) { + return; + } + assert.assert(_.uniq(makers).length === 1, ExchangeContractErrs.MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH); + const maker = makers[0]; + await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'maker', maker); + _.forEach(cancellationRequestsBatch, + async (cancellationRequest: OrderCancellationRequest, i: number) => { + assert.doesConformToSchema(`orderCancellationRequests[${i}].order`, + SchemaValidator.convertToJSONSchemaCompatibleObject(cancellationRequest.order as object), orderSchema); + assert.isBigNumber(`orderCancellationRequests[${i}].takerTokenCancelAmount`, + cancellationRequest.takerTokenCancelAmount); + await this.validateCancelOrderAndThrowIfInvalidAsync( + cancellationRequest.order, cancellationRequest.takerTokenCancelAmount); + }); const exchangeInstance = await this.getExchangeContractAsync(); - await this.validateCancelOrderAndThrowIfInvalidAsync(order, takerTokenCancelAmount); - - const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(order); - const gas = await exchangeInstance.cancel.estimateGas( + 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, takerTokenCancelAmounts] = + _.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts); + const gas = await exchangeInstance.batchCancel.estimateGas( orderAddresses, orderValues, - takerTokenCancelAmount, + takerTokenCancelAmounts, { - from: order.maker, + from: maker, }, ); - const response: ContractResponse = await exchangeInstance.cancel( + const response: ContractResponse = await exchangeInstance.batchCancel( orderAddresses, orderValues, - takerTokenCancelAmount, + takerTokenCancelAmounts, { - from: order.maker, + from: maker, gas, }, ); diff --git a/src/types.ts b/src/types.ts index cc145dc2e..00ef17189 100644 --- a/src/types.ts +++ b/src/types.ts @@ -74,6 +74,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; + }; fillOrKill: { (orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber, v: number, r: string, s: string, txOpts?: TxOpts): ContractResponse; @@ -145,6 +151,7 @@ export const ExchangeContractErrs = strEnum([ 'INSUFFICIENT_MAKER_FEE_BALANCE', 'INSUFFICIENT_MAKER_FEE_ALLOWANCE', 'TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER', + 'MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH', 'INSUFFICIENT_REMAINING_FILL_AMOUNT', ]); export type ExchangeContractErrs = keyof typeof ExchangeContractErrs; @@ -222,3 +229,8 @@ export interface SubscriptionOpts { } export type DoneCallback = (err?: Error) => void; + +export interface OrderCancellationRequest { + order: Order|SignedOrder; + takerTokenCancelAmount: BigNumber.BigNumber; +} |