From c71781d9abf7f2654a51dbef95bd18200ea2bde1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 18 Jul 2018 15:37:34 +0200 Subject: Merge --- .../asset_balance_and_proxy_allowance_fetcher.ts | 4 +- .../dependent_order_hashes_tracker.ts | 6 +- .../src/order_watcher/order_watcher.ts | 16 ++- .../order-watcher/test/expiration_watcher_test.ts | 4 +- packages/order-watcher/test/order_watcher_test.ts | 130 ++++++++++++++++++--- 5 files changed, 133 insertions(+), 27 deletions(-) (limited to 'packages/order-watcher') diff --git a/packages/order-watcher/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts b/packages/order-watcher/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts index b1c013928..bfa33c8b9 100644 --- a/packages/order-watcher/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts +++ b/packages/order-watcher/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts @@ -14,7 +14,7 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP this._stateLayer = stateLayer; } public async getBalanceAsync(assetData: string, userAddress: string): Promise { - const decodedAssetData = assetProxyUtils.decodeAssetData(assetData); + const decodedAssetData = assetProxyUtils.decodeAssetDataOrThrow(assetData); if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) { const decodedERC20AssetData = decodedAssetData as ERC20AssetData; const balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, { @@ -35,7 +35,7 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP } } public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { - const decodedAssetData = assetProxyUtils.decodeAssetData(assetData); + const decodedAssetData = assetProxyUtils.decodeAssetDataOrThrow(assetData); if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) { const decodedERC20AssetData = decodedAssetData as ERC20AssetData; const proxyAllowance = await this._erc20Token.getProxyAllowanceAsync( diff --git a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts index ae7d5078c..d639242ac 100644 --- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts +++ b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts @@ -54,7 +54,7 @@ export class DependentOrderHashesTracker { return dependentOrderHashes; } public getDependentOrderHashesByAssetDataByMaker(makerAddress: string, assetData: string): string[] { - const decodedAssetData = assetProxyUtils.decodeAssetData(assetData); + const decodedAssetData = assetProxyUtils.decodeAssetDataOrThrow(assetData); const dependentOrderHashes = decodedAssetData.assetProxyId === AssetProxyId.ERC20 ? this._getDependentOrderHashesByERC20AssetData(makerAddress, assetData) @@ -62,7 +62,7 @@ export class DependentOrderHashesTracker { return dependentOrderHashes; } public addToDependentOrderHashes(signedOrder: SignedOrder): void { - const decodedMakerAssetData = assetProxyUtils.decodeAssetData(signedOrder.makerAssetData); + const decodedMakerAssetData = assetProxyUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) { this._addToERC20DependentOrderHashes(signedOrder, (decodedMakerAssetData as ERC20AssetData).tokenAddress); } else { @@ -76,7 +76,7 @@ export class DependentOrderHashesTracker { this._addToMakerDependentOrderHashes(signedOrder); } public removeFromDependentOrderHashes(signedOrder: SignedOrder): void { - const decodedMakerAssetData = assetProxyUtils.decodeAssetData(signedOrder.makerAssetData); + const decodedMakerAssetData = assetProxyUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) { this._removeFromERC20DependentOrderhashes( signedOrder, diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts index 0ad3267d8..afc854445 100644 --- a/packages/order-watcher/src/order_watcher/order_watcher.ts +++ b/packages/order-watcher/src/order_watcher/order_watcher.ts @@ -28,7 +28,7 @@ import { orderHashUtils, OrderStateUtils, } from '@0xproject/order-utils'; -import { ExchangeContractErrs, OrderState, SignedOrder } from '@0xproject/types'; +import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder } from '@0xproject/types'; import { errorUtils, intervalUtils } from '@0xproject/utils'; import { BlockParamLiteral, LogEntryEvent, LogWithDecodedArgs, Provider } from 'ethereum-types'; import * as _ from 'lodash'; @@ -134,16 +134,26 @@ export class OrderWatcher { * signature is verified. * @param signedOrder The order you wish to start watching. */ - public addOrder(signedOrder: SignedOrder): void { + public async addOrderAsync(signedOrder: SignedOrder): Promise { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - assert.isValidSignatureAsync(this._provider, orderHash, signedOrder.signature, signedOrder.makerAddress); + await assert.isValidSignatureAsync(this._provider, orderHash, signedOrder.signature, signedOrder.makerAddress); const expirationUnixTimestampMs = signedOrder.expirationTimeSeconds.times(MILLISECONDS_IN_A_SECOND); this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs); this._orderByOrderHash[orderHash] = signedOrder; this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder); + + const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData]; + _.each(orderAssetDatas, assetData => { + const decodedAssetData = assetProxyUtils.decodeAssetDataOrThrow(assetData); + if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) { + this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress); + } else if (decodedAssetData.assetProxyId === AssetProxyId.ERC721) { + this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress); + } + }); } /** * Removes an order from the orderWatcher diff --git a/packages/order-watcher/test/expiration_watcher_test.ts b/packages/order-watcher/test/expiration_watcher_test.ts index 3c92ddb63..f765e8278 100644 --- a/packages/order-watcher/test/expiration_watcher_test.ts +++ b/packages/order-watcher/test/expiration_watcher_test.ts @@ -43,7 +43,6 @@ describe('ExpirationWatcher', () => { let expirationWatcher: ExpirationWatcher; before(async () => { await blockchainLifecycle.startAsync(); - const erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); zrxTokenAddress = tokenUtils.getProtocolTokenAddress(); fillScenarios = new FillScenarios( @@ -51,7 +50,8 @@ describe('ExpirationWatcher', () => { userAddresses, zrxTokenAddress, exchangeContractAddress, - erc20ProxyAddress, + contractWrappers.erc20Proxy.getContractAddress(), + contractWrappers.erc721Proxy.getContractAddress(), ); [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts index 1281d11c2..2363bb544 100644 --- a/packages/order-watcher/test/order_watcher_test.ts +++ b/packages/order-watcher/test/order_watcher_test.ts @@ -57,7 +57,6 @@ describe('OrderWatcher', () => { const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); before(async () => { await blockchainLifecycle.startAsync(); - const erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); zrxTokenAddress = tokenUtils.getProtocolTokenAddress(); exchangeContractAddress = contractWrappers.exchange.getContractAddress(); @@ -66,7 +65,8 @@ describe('OrderWatcher', () => { userAddresses, zrxTokenAddress, exchangeContractAddress, - erc20ProxyAddress, + contractWrappers.erc20Proxy.getContractAddress(), + contractWrappers.erc721Proxy.getContractAddress(), ); [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); @@ -74,7 +74,7 @@ describe('OrderWatcher', () => { assetProxyUtils.encodeERC20AssetData(makerTokenAddress), assetProxyUtils.encodeERC20AssetData(takerTokenAddress), ]; - const orderWatcherConfig = { stateLayer: BlockParamLiteral.Latest }; + const orderWatcherConfig = {}; orderWatcher = new OrderWatcher(provider, networkId, orderWatcherConfig); }); after(async () => { @@ -96,7 +96,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); expect((orderWatcher as any)._orderByOrderHash).to.include({ [orderHash]: signedOrder, }); @@ -156,7 +156,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; @@ -180,7 +180,7 @@ describe('OrderWatcher', () => { takerAddress, fillableAmount, ); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => { throw new Error('OrderState callback fired for irrelevant order'); }); @@ -209,7 +209,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; @@ -237,7 +237,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); @@ -263,7 +263,7 @@ describe('OrderWatcher', () => { const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress); const fillAmountInBaseUnits = new BigNumber(2); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); @@ -299,7 +299,7 @@ describe('OrderWatcher', () => { takerAddress, ); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); orderWatcher.subscribe(callback); await contractWrappers.erc20Token.setProxyAllowanceAsync( zrxTokenAddress, @@ -323,7 +323,7 @@ describe('OrderWatcher', () => { ); const fillAmountInBaseUnits = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); const validOrderState = orderState as OrderStateValid; @@ -351,7 +351,7 @@ describe('OrderWatcher', () => { ); const changedMakerApprovalAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; @@ -388,7 +388,7 @@ describe('OrderWatcher', () => { const remainingAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals); const transferAmount = makerBalance.sub(remainingAmount); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.true(); @@ -429,7 +429,7 @@ describe('OrderWatcher', () => { const remainingTokenAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(4), decimals); const transferTokenAmount = makerFee.sub(remainingTokenAmount); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; @@ -467,7 +467,7 @@ describe('OrderWatcher', () => { feeRecipient, ); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { const validOrderState = orderState as OrderStateValid; @@ -495,7 +495,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); @@ -518,7 +518,7 @@ describe('OrderWatcher', () => { fillableAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.addOrder(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); @@ -534,5 +534,101 @@ describe('OrderWatcher', () => { ); })().catch(done); }); + describe('erc721', () => { + let makerErc721AssetData: string; + let makerErc721TokenAddress: string; + const tokenId = new BigNumber(42); + [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses(); + makerErc721AssetData = assetProxyUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId); + const fillableErc721Amount = new BigNumber(1); + it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => { + (async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerErc721AssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableErc721Amount, + ); + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); + const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { + expect(orderState.isValid).to.be.false(); + const invalidOrderState = orderState as OrderStateInvalid; + expect(invalidOrderState.orderHash).to.be.equal(orderHash); + expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); + }); + orderWatcher.subscribe(callback); + await contractWrappers.erc721Token.setApprovalAsync( + makerErc721TokenAddress, + constants.NULL_ADDRESS, + tokenId, + ); + })().catch(done); + }); + it('should emit orderStateInvalid when maker allowance for all set to 0 for watched order', (done: DoneCallback) => { + (async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerErc721AssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableErc721Amount, + ); + await contractWrappers.erc721Token.setApprovalAsync( + makerErc721TokenAddress, + constants.NULL_ADDRESS, + tokenId, + ); + let isApproved = true; + await contractWrappers.erc721Token.setProxyApprovalForAllAsync( + makerErc721TokenAddress, + makerAddress, + isApproved, + ); + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); + const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { + expect(orderState.isValid).to.be.false(); + const invalidOrderState = orderState as OrderStateInvalid; + expect(invalidOrderState.orderHash).to.be.equal(orderHash); + expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); + }); + orderWatcher.subscribe(callback); + isApproved = false; + await contractWrappers.erc721Token.setProxyApprovalForAllAsync( + makerErc721TokenAddress, + makerAddress, + isApproved, + ); + })().catch(done); + }); + it('should emit orderStateInvalid when maker moves NFT backing watched order', (done: DoneCallback) => { + (async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerErc721AssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableErc721Amount, + ); + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + await orderWatcher.addOrderAsync(signedOrder); + const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { + expect(orderState.isValid).to.be.false(); + const invalidOrderState = orderState as OrderStateInvalid; + expect(invalidOrderState.orderHash).to.be.equal(orderHash); + expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); + }); + orderWatcher.subscribe(callback); + await contractWrappers.erc721Token.transferFromAsync( + makerErc721TokenAddress, + coinbase, + makerAddress, + tokenId, + ); + })().catch(done); + }); + }); }); }); // tslint:disable:max-file-line-count -- cgit v1.2.3