aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts60
-rw-r--r--src/types.ts12
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;
+}