diff options
Diffstat (limited to 'src/contract_wrappers')
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index d144d8aad..8d95c9fae 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -20,6 +20,7 @@ import { EventCallback, ContractResponse, OrderCancellationRequest, + OrderFillRequest, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -126,31 +127,31 @@ export class ExchangeWrapper extends ContractWrapper { return cancelledAmountInBaseUnits; } /** - * Fills a signed order with a fillAmount denominated in baseUnits of the taker token. + * Fills a signed order with a takerTokenFillAmount denominated in baseUnits of the taker token. * Since the order in which transactions are included in the next block is indeterminate, race-conditions * could arise where a users balance or allowance changes before the fillOrder executes. Because of this, * we allow you to specify `shouldCheckTransfer`. If true, the smart contract will not throw if while * executing, the parties do not have sufficient balances/allowances, preserving gas costs. Setting it to * false forgoes this check and causes the smart contract to throw instead. */ - public async fillOrderAsync(signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, + public async fillOrderAsync(signedOrder: SignedOrder, takerTokenFillAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, takerAddress: string): Promise<void> { assert.doesConformToSchema('signedOrder', - SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), - signedOrderSchema); - assert.isBigNumber('fillTakerAmount', fillTakerAmount); + SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), + signedOrderSchema); + assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); const exchangeInstance = await this.getExchangeContractAsync(); - await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress); + await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, takerTokenFillAmount, takerAddress); const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(signedOrder); const gas = await exchangeInstance.fill.estimateGas( orderAddresses, orderValues, - fillTakerAmount, + takerTokenFillAmount, shouldCheckTransfer, signedOrder.ecSignature.v, signedOrder.ecSignature.r, @@ -162,7 +163,7 @@ export class ExchangeWrapper extends ContractWrapper { const response: ContractResponse = await exchangeInstance.fill( orderAddresses, orderValues, - fillTakerAmount, + takerTokenFillAmount, shouldCheckTransfer, signedOrder.ecSignature.v, signedOrder.ecSignature.r, @@ -175,6 +176,67 @@ export class ExchangeWrapper extends ContractWrapper { this.throwErrorLogsAsErrors(response.logs); } /** + * Batched version of fillOrderAsync. Executes fills atomically in a single transaction. + */ + public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[], + shouldCheckTransfer: boolean, takerAddress: string): Promise<void> { + if (_.isEmpty(orderFillRequests)) { + return; + } + assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); + _.forEach(orderFillRequests, + async (orderFillRequest: OrderFillRequest) => { + assert.doesConformToSchema('signedOrder', + SchemaValidator.convertToJSONSchemaCompatibleObject(orderFillRequest.signedOrder as object), + signedOrderSchema); + assert.isBigNumber('takerTokenFillAmount', orderFillRequest.takerTokenFillAmount); + await this.validateFillOrderAndThrowIfInvalidAsync( + orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, takerAddress); + }); + const exchangeInstance = await this.getExchangeContractAsync(); + + const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => { + return [ + ...ExchangeWrapper.getOrderAddressesAndValues(orderFillRequest.signedOrder), + orderFillRequest.takerTokenFillAmount, + orderFillRequest.signedOrder.ecSignature.v, + orderFillRequest.signedOrder.ecSignature.r, + orderFillRequest.signedOrder.ecSignature.s, + ]; + }); + // _.unzip doesn't type check if values have different types :'( + const [orderAddressesArray, orderValuesArray, takerTokenFillAmountArray, vArray, rArray, sArray] = _.unzip<any>( + orderAddressesValuesAmountsAndSignatureArray, + ); + const gas = await exchangeInstance.batchFill.estimateGas( + orderAddressesArray, + orderValuesArray, + takerTokenFillAmountArray, + shouldCheckTransfer, + vArray, + rArray, + sArray, + { + from: takerAddress, + }, + ); + const response: ContractResponse = await exchangeInstance.batchFill( + orderAddressesArray, + orderValuesArray, + takerTokenFillAmountArray, + shouldCheckTransfer, + vArray, + rArray, + sArray, + { + from: takerAddress, + gas, + }, + ); + this.throwErrorLogsAsErrors(response.logs); + } + /** * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled, * the fill order is abandoned. */ |