diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2018-07-18 22:38:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-18 22:38:16 +0800 |
commit | 00d1622b3f087943e750f1b3f6ee6ceab7e80285 (patch) | |
tree | 44789fff181ec24846728d885ba541c23f682321 /packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts | |
parent | e2fb49a8f871fd4b631bb01bb641c632b7c19435 (diff) | |
parent | a1acf19ff3c1948214dde05a91eb3fbeac728d2c (diff) | |
download | dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar.gz dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar.bz2 dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar.lz dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar.xz dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.tar.zst dexon-sol-tools-00d1622b3f087943e750f1b3f6ee6ceab7e80285.zip |
Merge pull request #887 from 0xProject/feature/order-watcher-v2
Order watcher v2
Diffstat (limited to 'packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts')
-rw-r--r-- | packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts | 230 |
1 files changed, 230 insertions, 0 deletions
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 new file mode 100644 index 000000000..cc70bd5d7 --- /dev/null +++ b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts @@ -0,0 +1,230 @@ +// tslint:disable:no-unnecessary-type-assertion +import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils'; +import { AssetProxyId, ERC20AssetData, ERC721AssetData, SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +export interface OrderHashesByMakerAddress { + [makerAddress: string]: Set<string>; +} + +export interface OrderHashesByERC20ByMakerAddress { + [makerAddress: string]: { + [erc20TokenAddress: string]: Set<string>; + }; +} + +export interface OrderHashesByERC721AddressByTokenIdByMakerAddress { + [makerAddress: string]: { + [erc721TokenAddress: string]: { + // Ideally erc721TokenId should be a BigNumber, but it's not a valid index type so we just convert it to a string before using it as an index + [erc721TokenId: string]: Set<string>; + }; + }; +} + +/** + */ +export class DependentOrderHashesTracker { + private readonly _zrxTokenAddress: string; + // `_orderHashesByMakerAddress` is redundant and could be generated from + // `_orderHashesByERC20ByMakerAddress` and `_orderHashesByERC721AddressByTokenIdByMakerAddress` + // on the fly by merging all the entries together but it's more complex and computationally heavy. + // We might change that in future if we're move memory-constrained. + private readonly _orderHashesByMakerAddress: OrderHashesByMakerAddress = {}; + private readonly _orderHashesByERC20ByMakerAddress: OrderHashesByERC20ByMakerAddress = {}; + private readonly _orderHashesByERC721AddressByTokenIdByMakerAddress: OrderHashesByERC721AddressByTokenIdByMakerAddress = {}; + constructor(zrxTokenAddress: string) { + this._zrxTokenAddress = zrxTokenAddress; + } + public getDependentOrderHashesByERC721ByMaker(makerAddress: string, tokenAddress: string): string[] { + const orderHashSets = _.values( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress], + ); + const orderHashList = _.reduce( + orderHashSets, + (accumulator, orderHashSet) => [...accumulator, ...orderHashSet], + [] as string[], + ); + const uniqueOrderHashList = _.uniq(orderHashList); + return uniqueOrderHashList; + } + public getDependentOrderHashesByMaker(makerAddress: string): string[] { + const dependentOrderHashes = Array.from(this._orderHashesByMakerAddress[makerAddress]); + return dependentOrderHashes; + } + public getDependentOrderHashesByAssetDataByMaker(makerAddress: string, assetData: string): string[] { + const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); + const dependentOrderHashes = + decodedAssetData.assetProxyId === AssetProxyId.ERC20 + ? this._getDependentOrderHashesByERC20AssetData(makerAddress, assetData) + : this._getDependentOrderHashesByERC721AssetData(makerAddress, assetData); + 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._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._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); + this._removeFromMakerDependentOrderhashes(signedOrder); + } + private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] { + const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress; + let dependentOrderHashes: string[] = []; + if ( + !_.isUndefined(this._orderHashesByERC20ByMakerAddress[makerAddress]) && + !_.isUndefined(this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress]) + ) { + dependentOrderHashes = Array.from(this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress]); + } + return dependentOrderHashes; + } + private _getDependentOrderHashesByERC721AssetData(makerAddress: string, erc721AssetData: string): string[] { + const tokenAddress = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenAddress; + const tokenId = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenId; + let dependentOrderHashes: string[] = []; + if ( + !_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress]) && + !_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress]) && + !_.isUndefined( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()], + ) + ) { + dependentOrderHashes = Array.from( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()], + ); + } + return dependentOrderHashes; + } + private _addToERC20DependentOrderHashes(signedOrder: SignedOrder, erc20TokenAddress: string): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + if (_.isUndefined(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress])) { + this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] = {}; + } + if (_.isUndefined(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress])) { + this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress] = new Set(); + } + this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].add(orderHash); + } + private _addToERC721DependentOrderHashes( + signedOrder: SignedOrder, + erc721TokenAddress: string, + tokenId: BigNumber, + ): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + if (_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress])) { + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] = {}; + } + + if ( + _.isUndefined( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress], + ) + ) { + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] = {}; + } + + if ( + _.isUndefined( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ + tokenId.toString() + ], + ) + ) { + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ + tokenId.toString() + ] = new Set(); + } + + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ + tokenId.toString() + ].add(orderHash); + } + private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) { + this._orderHashesByMakerAddress[signedOrder.makerAddress] = new Set(); + } + this._orderHashesByMakerAddress[signedOrder.makerAddress].add(orderHash); + } + private _removeFromERC20DependentOrderhashes(signedOrder: SignedOrder, erc20TokenAddress: string): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].delete(orderHash); + + if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress])) { + delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress]; + } + + if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress])) { + delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress]; + } + } + private _removeFromERC721DependentOrderhashes( + signedOrder: SignedOrder, + erc721TokenAddress: string, + tokenId: BigNumber, + ): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ + tokenId.toString() + ].delete(orderHash); + + if ( + _.isEmpty( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ + tokenId.toString() + ], + ) + ) { + delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][ + erc721TokenAddress + ][tokenId.toString()]; + } + + if ( + _.isEmpty( + this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress], + ) + ) { + delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][ + erc721TokenAddress + ]; + } + + if (_.isEmpty(this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress])) { + delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress]; + } + } + private _removeFromMakerDependentOrderhashes(signedOrder: SignedOrder): void { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + this._orderHashesByMakerAddress[signedOrder.makerAddress].delete(orderHash); + + if (_.isEmpty(this._orderHashesByMakerAddress[signedOrder.makerAddress])) { + delete this._orderHashesByMakerAddress[signedOrder.makerAddress]; + } + } +} |