From 67dfe6030c3d193e8ccf9411b114a44e2ed11c73 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Sat, 1 Dec 2018 22:30:32 -0800 Subject: feat: Add support for MultiAssetProxy --- .../dependent_order_hashes_tracker.ts | 76 +++++++++----- .../src/order_watcher/order_watcher.ts | 110 +++++++++++++++------ 2 files changed, 131 insertions(+), 55 deletions(-) (limited to 'packages/order-watcher/src') 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 a956a94db..eed1d055b 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 @@ -1,6 +1,6 @@ // tslint:disable:no-unnecessary-type-assertion import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { AssetProxyId, ERC20AssetData, ERC721AssetData, SignedOrder } from '@0x/types'; +import { AssetProxyId, ERC20AssetData, ERC721AssetData, MultiAssetData, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; @@ -62,39 +62,20 @@ export class DependentOrderHashesTracker { return dependentOrderHashes; } public addToDependentOrderHashes(signedOrder: SignedOrder): void { - const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); - if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) { - this._addToERC20DependentOrderHashes(signedOrder, (decodedMakerAssetData as ERC20AssetData).tokenAddress); - } else { - this._addToERC721DependentOrderHashes( - signedOrder, - (decodedMakerAssetData as ERC721AssetData).tokenAddress, - (decodedMakerAssetData as ERC721AssetData).tokenId, - ); - } + this._addAssetDataToDependentOrderHashes(signedOrder, signedOrder.makerAssetData); this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress); this._addToMakerDependentOrderHashes(signedOrder); } public removeFromDependentOrderHashes(signedOrder: SignedOrder): void { - const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); - if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) { - this._removeFromERC20DependentOrderhashes( - signedOrder, - (decodedMakerAssetData as ERC20AssetData).tokenAddress, - ); - } else { - this._removeFromERC721DependentOrderhashes( - signedOrder, - (decodedMakerAssetData as ERC721AssetData).tokenAddress, - (decodedMakerAssetData as ERC721AssetData).tokenId, - ); - } + this._removeAssetDataFromDependentOrderHashes(signedOrder, signedOrder.makerAssetData); // If makerToken === ZRX then we already removed it and we don't need to remove it again. + const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); if ((decodedMakerAssetData as ERC20AssetData).tokenAddress !== this._zrxTokenAddress) { this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); } this._removeFromMakerDependentOrderhashes(signedOrder); } + private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] { const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress; let dependentOrderHashes: string[] = []; @@ -167,6 +148,28 @@ export class DependentOrderHashesTracker { tokenId.toString() ].add(orderHash); } + private _addAssetDataToDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void { + const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); + switch (decodedAssetData.assetProxyId) { + case AssetProxyId.ERC20: + this._addToERC20DependentOrderHashes(signedOrder, (decodedAssetData as ERC20AssetData).tokenAddress); + break; + case AssetProxyId.ERC721: + this._addToERC721DependentOrderHashes( + signedOrder, + (decodedAssetData as ERC721AssetData).tokenAddress, + (decodedAssetData as ERC721AssetData).tokenId, + ); + break; + case AssetProxyId.MultiAsset: + _.each((decodedAssetData as MultiAssetData).nestedAssetData, nestedAssetDataElement => + this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement), + ); + break; + default: + break; + } + } private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void { const orderHash = orderHashUtils.getOrderHashHex(signedOrder); if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) { @@ -230,4 +233,29 @@ export class DependentOrderHashesTracker { delete this._orderHashesByMakerAddress[signedOrder.makerAddress]; } } + private _removeAssetDataFromDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void { + const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); + switch (decodedAssetData.assetProxyId) { + case AssetProxyId.ERC20: + this._removeFromERC20DependentOrderhashes( + signedOrder, + (decodedAssetData as ERC20AssetData).tokenAddress, + ); + break; + case AssetProxyId.ERC721: + this._removeFromERC721DependentOrderhashes( + signedOrder, + (decodedAssetData as ERC721AssetData).tokenAddress, + (decodedAssetData as ERC721AssetData).tokenId, + ); + break; + case AssetProxyId.MultiAsset: + _.each((decodedAssetData as MultiAssetData).nestedAssetData, nestedAssetDataElement => + this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement), + ); + break; + default: + break; + } + } } diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts index 96c5ca7b4..bf890f0e6 100644 --- a/packages/order-watcher/src/order_watcher/order_watcher.ts +++ b/packages/order-watcher/src/order_watcher/order_watcher.ts @@ -32,7 +32,16 @@ import { orderHashUtils, OrderStateUtils, } from '@0x/order-utils'; -import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder, Stats } from '@0x/types'; +import { + AssetProxyId, + ERC20AssetData, + ERC721AssetData, + ExchangeContractErrs, + MultiAssetData, + OrderState, + SignedOrder, + Stats, +} from '@0x/types'; import { errorUtils, intervalUtils } from '@0x/utils'; import { BlockParamLiteral, LogEntryEvent, LogWithDecodedArgs, Provider } from 'ethereum-types'; import * as _ from 'lodash'; @@ -161,14 +170,7 @@ export class OrderWatcher { this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder); const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData]; - _.each(orderAssetDatas, assetData => { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) { - this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress); - } else if (decodedAssetData.assetProxyId === AssetProxyId.ERC721) { - this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress); - } - }); + _.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData)); } /** * Removes an order from the orderWatcher @@ -236,31 +238,77 @@ export class OrderWatcher { await this._emitRevalidateOrdersAsync([orderHash]); } } + private _addAssetDataToAbiDecoder(assetData: string): void { + const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); + switch (decodedAssetData.assetProxyId) { + case AssetProxyId.ERC20: + this._collisionResistantAbiDecoder.addERC20Token((decodedAssetData as ERC20AssetData).tokenAddress); + break; + case AssetProxyId.ERC721: + this._collisionResistantAbiDecoder.addERC721Token((decodedAssetData as ERC721AssetData).tokenAddress); + break; + case AssetProxyId.MultiAsset: + _.each((decodedAssetData as MultiAssetData).nestedAssetData, nestedAssetDataElement => + this._addAssetDataToAbiDecoder(nestedAssetDataElement), + ); + break; + default: + break; + } + } + private _deleteLazyStoreBalance(assetData: string, userAddress: string): void { + const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); + switch (assetProxyId) { + case AssetProxyId.ERC20: + case AssetProxyId.ERC721: + this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress); + break; + case AssetProxyId.MultiAsset: + const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData); + _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => + this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress), + ); + break; + default: + break; + } + } + private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void { + const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); + switch (assetProxyId) { + case AssetProxyId.ERC20: + case AssetProxyId.ERC721: + this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress); + break; + case AssetProxyId.MultiAsset: + const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData); + _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => + this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress), + ); + break; + default: + break; + } + } private _cleanupOrderRelatedState(orderHash: string): void { const signedOrder = this._orderByOrderHash[orderHash]; this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash); this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.makerAssetData, signedOrder.makerAddress); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance( - signedOrder.makerAssetData, - signedOrder.makerAddress, - ); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.takerAssetData, signedOrder.takerAddress); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance( - signedOrder.takerAssetData, - signedOrder.takerAddress, - ); + this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress); + this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress); + this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress); + this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress); const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData(); if (!signedOrder.makerFee.isZero()) { - this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.makerAddress); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.makerAddress); + this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress); + this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress); } if (!signedOrder.takerFee.isZero()) { - this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.takerAddress); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.takerAddress); + this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress); + this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress); } } private _onOrderExpired(orderHash: string): void { @@ -302,7 +350,7 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as ERC20TokenApprovalEventArgs; const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner); + this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._owner, @@ -315,7 +363,7 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as ERC721TokenApprovalEventArgs; const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId); - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner); + this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._owner, @@ -333,8 +381,8 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as ERC20TokenTransferEventArgs; const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to); + this._deleteLazyStoreBalance(tokenAssetData, args._from); + this._deleteLazyStoreBalance(tokenAssetData, args._to); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._from, @@ -347,8 +395,8 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as ERC721TokenTransferEventArgs; const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to); + this._deleteLazyStoreBalance(tokenAssetData, args._from); + this._deleteLazyStoreBalance(tokenAssetData, args._to); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._from, @@ -375,7 +423,7 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as WETH9DepositEventArgs; const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner); + this._deleteLazyStoreBalance(tokenAssetData, args._owner); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._owner, @@ -388,7 +436,7 @@ export class OrderWatcher { // Invalidate cache const args = decodedLog.args as WETH9WithdrawalEventArgs; const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner); + this._deleteLazyStoreBalance(tokenAssetData, args._owner); // Revalidate orders const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( args._owner, -- cgit v1.2.3