From 857a35d4f71c1c954033c3b0505250e18be21cfb Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 9 Nov 2018 00:45:48 +0100 Subject: Fix validateOrderFillableOrThrowAsync method so it also checks order signature, cancelled, cancelledUpTo, and throws helpful error messages --- .../src/contract_wrappers/exchange_wrapper.ts | 17 +++++++++++++++++ .../src/fetchers/order_filled_cancelled_fetcher.ts | 16 +++++++++++++--- .../src/schemas/validate_order_fillable_opts_schema.ts | 7 +++++++ .../contract-wrappers/test/exchange_wrapper_test.ts | 12 ++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts (limited to 'packages/contract-wrappers') diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts index 2e978f35b..902fc755c 100644 --- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts @@ -5,7 +5,9 @@ import { assetDataUtils, BalanceAndProxyAllowanceLazyStore, ExchangeTransferSimulator, + orderHashUtils, OrderValidationUtils, + signatureUtils, } from '@0x/order-utils'; import { AssetProxyId, Order, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -18,6 +20,7 @@ import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_ import { methodOptsSchema } from '../schemas/method_opts_schema'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; +import { validateOrderFillableOptsSchema } from '../schemas/validate_order_fillable_opts_schema'; import { BlockRange, EventCallback, @@ -1114,6 +1117,20 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder: SignedOrder, opts: ValidateOrderFillableOpts = {}, ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.doesConformToSchema('opts', opts, validateOrderFillableOptsSchema); + + const orderHash = await orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureUtils.isValidSignatureAsync( + this._web3Wrapper.getProvider(), + orderHash, + signedOrder.signature, + signedOrder.makerAddress, + ); + if (!isValidSignature) { + throw new Error('INVALID_ORDER_SIGNATURE'); + } + const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher( this._erc20TokenWrapper, this._erc721TokenWrapper, diff --git a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts index acf7038fa..5d350916c 100644 --- a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts +++ b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts @@ -1,5 +1,6 @@ // tslint:disable:no-unnecessary-type-assertion -import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils'; +import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils'; +import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { BlockParamLiteral } from 'ethereum-types'; @@ -18,9 +19,18 @@ export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelled }); return filledTakerAmount; } - public async isOrderCancelledAsync(orderHash: string): Promise { + public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const isCancelled = await this._exchange.isCancelledAsync(orderHash); - return isCancelled; + const orderEpoch = await this._exchange.getOrderEpochAsync( + signedOrder.makerAddress, + signedOrder.senderAddress, + { + defaultBlock: this._stateLayer, + }, + ); + const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt; + return isCancelled || isCancelledByOrderEpoch; } public getZRXAssetData(): string { const zrxAssetData = this._exchange.getZRXAssetData(); diff --git a/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts b/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts new file mode 100644 index 000000000..2e111af04 --- /dev/null +++ b/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts @@ -0,0 +1,7 @@ +export const validateOrderFillableOptsSchema = { + id: '/ValidateOrderFillableOpts', + properties: { + expectedFillTakerTokenAmount: { $ref: '/wholeNumberSchema' }, + }, + type: 'object', +}; diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts index 0e537bd83..8058be873 100644 --- a/packages/contract-wrappers/test/exchange_wrapper_test.ts +++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts @@ -282,6 +282,18 @@ describe('ExchangeWrapper', () => { expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash); }); }); + describe('#validateOrderFillableOrThrowAsync', () => { + it('should throw if signature is invalid', async () => { + const signedOrderWithInvalidSignature = { + ...signedOrder, + signature: '0xdeadbeef', + }; + + expect( + contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrderWithInvalidSignature), + ).to.eventually.to.be.rejected(); + }); + }); describe('#isValidSignature', () => { it('should check if the signature is valid', async () => { const orderHash = orderHashUtils.getOrderHashHex(signedOrder); -- cgit v1.2.3