From 5e92ca039c593028694a1453b39e55c127e96ba5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 26 Sep 2017 11:01:33 +0200 Subject: Add validateOrderFillableThrowIfNotFillableAsync to public methods in order to validate orders in an orderbook without a specific taker in mind --- src/contract_wrappers/exchange_wrapper.ts | 19 +++++++++++++++++++ src/types.ts | 10 ++++++++++ src/utils/order_validation_utils.ts | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 54d7f62d5..b56431082 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -28,6 +28,7 @@ import { LogCancelContractEventArgs, LogWithDecodedArgs, MethodOpts, + ValidateOrderFillableOpts, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -623,6 +624,24 @@ export class ExchangeWrapper extends ContractWrapper { const exchangeAddress = exchangeInstance.address; return exchangeAddress; } + /** + * Checks if order is still fillable and throws an error otherwise. + * @param signedOrder An object that conforms to the SignedOrder interface. The + * signedOrder you wish to validate. + * @param opts An object that conforms to the ValidateOrderFillableOpts + * interface. Allows specifying a specific fillTakerTokenAmount + * to validate for. + */ + public async validateOrderFillableThrowIfNotFillableAsync( + signedOrder: SignedOrder, opts: ValidateOrderFillableOpts, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + const zrxTokenAddress = await this._getZRXTokenAddressAsync(); + const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined; + await this._orderValidationUtils.validateOrderFillableThrowIfNotFillableAsync( + signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount, + ); + } /** * Checks if order fill will succeed and throws an error otherwise. * @param signedOrder An object that conforms to the SignedOrder interface. The diff --git a/src/types.ts b/src/types.ts index 29fb40e73..92d1e51f6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -433,6 +433,16 @@ export interface Artifact { }}; } +/* + * expectedFillTakerTokenAmount: If specified, the validation method will ensure that the + * supplied order's maker has a sufficient allowance/balance to fill this amount of the order's + * takerTokenAmount. If not specified, the validation method ensures that the maker has a sufficient + * allowance/balance to fill the entire remaining order. + */ +export interface ValidateOrderFillableOpts { + expectedFillTakerTokenAmount?: BigNumber.BigNumber; +} + /* * defaultBlock: The block up to which to query the blockchain state. Setting this to a historical block number * let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the diff --git a/src/utils/order_validation_utils.ts b/src/utils/order_validation_utils.ts index 815cd0115..27fc72dca 100644 --- a/src/utils/order_validation_utils.ts +++ b/src/utils/order_validation_utils.ts @@ -1,3 +1,4 @@ +import * as _ from 'lodash'; import {ExchangeContractErrs, SignedOrder, Order, ZeroExError} from '../types'; import {ZeroEx} from '../0x'; import {TokenWrapper} from '../contract_wrappers/token_wrapper'; @@ -12,6 +13,26 @@ export class OrderValidationUtils { this.tokenWrapper = tokenWrapper; this.exchangeWrapper = exchangeWrapper; } + public async validateOrderFillableThrowIfNotFillableAsync( + signedOrder: SignedOrder, zrxTokenAddress: string, expectedFillTakerTokenAmount?: BigNumber.BigNumber, + ): Promise { + const orderHash = utils.getOrderHashHex(signedOrder); + const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + if (signedOrder.makerTokenAmount.eq(unavailableTakerTokenAmount)) { + throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); + } + const currentUnixTimestampSec = utils.getCurrentUnixTimestamp(); + if (signedOrder.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { + throw new Error(ExchangeContractErrs.OrderFillExpired); + } + let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); + if (!_.isUndefined(expectedFillTakerTokenAmount)) { + fillTakerTokenAmount = expectedFillTakerTokenAmount; + } + await this.validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync( + signedOrder, fillTakerTokenAmount, zrxTokenAddress, + ); + } public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber.BigNumber, takerAddress: string, -- cgit v1.2.3