aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts77
-rw-r--r--src/types.ts11
2 files changed, 81 insertions, 7 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index 4f132656e..901ea4749 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -10,6 +10,7 @@ import {
OrderValues,
OrderAddresses,
Order,
+ OrderFillOrKillRequest,
SignedOrder,
ContractEvent,
ExchangeEvents,
@@ -188,13 +189,8 @@ export class ExchangeWrapper extends ContractWrapper {
const exchangeInstance = await this.getExchangeContractAsync();
await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress);
- // Check that fillValue available >= fillTakerAmount
- const orderHashHex = await this.getOrderHashHexAsync(signedOrder);
- const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex);
- const remainingTakerAmount = signedOrder.takerTokenAmount.minus(unavailableTakerAmount);
- if (remainingTakerAmount < fillTakerAmount) {
- throw new Error(ExchangeContractErrs.INSUFFICIENT_REMAINING_FILL_AMOUNT);
- }
+ await this.validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder, exchangeInstance.address,
+ fillTakerAmount);
const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(signedOrder);
@@ -224,6 +220,62 @@ export class ExchangeWrapper extends ContractWrapper {
this.throwErrorLogsAsErrors(response.logs);
}
/**
+ * Batch version of fillOrKill. Allows a taker to specify a batch of orders that will either be atomically
+ * filled to the desired fillAmount or aborted.
+ */
+ public async batchFillOrKillAsync(orderFillOrKillRequests: OrderFillOrKillRequest[],
+ takerAddress: string) {
+ await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper);
+ const exchangeInstance = await this.getExchangeContractAsync();
+ _.each(orderFillOrKillRequests, request => {
+ assert.doesConformToSchema('signedOrder',
+ SchemaValidator.convertToJSONSchemaCompatibleObject(request.signedOrder as object),
+ signedOrderSchema);
+ assert.isBigNumber('fillTakerAmount', request.fillTakerAmount);
+ this.validateFillOrKillOrderAndThrowIfInvalidAsync(request.signedOrder,
+ exchangeInstance.address,
+ request.fillTakerAmount);
+ });
+
+ const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillOrKillRequests, request => {
+ return [
+ ...ExchangeWrapper.getOrderAddressesAndValues(request.signedOrder),
+ request.fillTakerAmount,
+ request.signedOrder.ecSignature.v,
+ request.signedOrder.ecSignature.r,
+ request.signedOrder.ecSignature.s,
+ ];
+ });
+
+ const [orderAddresses, orderValues, fillTakerAmounts, vParams, rParams, sParams] =
+ _.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts);
+
+ const gas = await exchangeInstance.batchFillOrKill.estimateGas(
+ orderAddresses,
+ orderValues,
+ fillTakerAmounts,
+ vParams,
+ rParams,
+ sParams,
+ {
+ from: takerAddress,
+ },
+ );
+ const response: ContractResponse = await exchangeInstance.batchFillOrKill(
+ orderAddresses,
+ orderValues,
+ fillTakerAmounts,
+ vParams,
+ rParams,
+ sParams,
+ {
+ from: takerAddress,
+ gas,
+ },
+ );
+ this.throwErrorLogsAsErrors(response.logs);
+ }
+ /**
* Cancel a given fill amount of an order. Cancellations are cumulative.
*/
public async cancelOrderAsync(order: Order|SignedOrder, takerTokenCancelAmount: BigNumber.BigNumber):
@@ -334,6 +386,17 @@ export class ExchangeWrapper extends ContractWrapper {
throw new Error(ExchangeContractErrs.ORDER_CANCEL_EXPIRED);
}
}
+ private async validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder: SignedOrder,
+ exchangeAddress: string,
+ fillTakerAmount: BigNumber.BigNumber) {
+ // Check that fillValue available >= fillTakerAmount
+ const orderHashHex = utils.getOrderHashHex(signedOrder, exchangeAddress);
+ const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex);
+ const remainingTakerAmount = signedOrder.takerTokenAmount.minus(unavailableTakerAmount);
+ if (remainingTakerAmount < fillTakerAmount) {
+ throw new Error(ExchangeContractErrs.INSUFFICIENT_REMAINING_FILL_AMOUNT);
+ }
+ }
/**
* This method does not currently validate the edge-case where the makerToken or takerToken is also the token used
* to pay fees (ZRX). It is possible for them to have enough for fees and the transfer but not both.
diff --git a/src/types.ts b/src/types.ts
index cc145dc2e..d19fb2d43 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -80,6 +80,12 @@ export interface ExchangeContract extends ContractInstance {
estimateGas: (orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber,
v: number, r: string, s: string, txOpts?: TxOpts) => number;
};
+ batchFillOrKill: {
+ (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillValuesT: BigNumber.BigNumber[],
+ v: number[], r: string[], s: string[], txOpts: TxOpts): ContractResponse;
+ estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillValuesT: BigNumber.BigNumber[],
+ v: number[], r: string[], s: string[], txOpts?: TxOpts) => number;
+ };
filled: {
call: (orderHash: string) => BigNumber.BigNumber;
};
@@ -222,3 +228,8 @@ export interface SubscriptionOpts {
}
export type DoneCallback = (err?: Error) => void;
+
+export interface OrderFillOrKillRequest {
+ signedOrder: SignedOrder;
+ fillTakerAmount: BigNumber.BigNumber;
+}