diff options
Diffstat (limited to 'packages')
11 files changed, 247 insertions, 328 deletions
diff --git a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts index 376004f52..1ff130a48 100644 --- a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts +++ b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts @@ -1,6 +1,4 @@ -// tslint:disable:no-unnecessary-type-assertion import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils'; -import { AssetProxyId, ERC20AssetData, ERC721AssetData, MultiAssetData } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { BlockParamLiteral } from 'ethereum-types'; import * as _ from 'lodash'; @@ -20,99 +18,73 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> { const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); let balance: BigNumber | undefined; - switch (decodedAssetData.assetProxyId) { - case AssetProxyId.ERC20: - const decodedERC20AssetData = decodedAssetData as ERC20AssetData; - balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, { + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + balance = await this._erc20Token.getBalanceAsync(decodedAssetData.tokenAddress, userAddress, { + defaultBlock: this._stateLayer, + }); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + const tokenOwner = await this._erc721Token.getOwnerOfAsync( + decodedAssetData.tokenAddress, + decodedAssetData.tokenId, + { defaultBlock: this._stateLayer, - }); - break; - case AssetProxyId.ERC721: - const decodedERC721AssetData = decodedAssetData as ERC721AssetData; - const tokenOwner = await this._erc721Token.getOwnerOfAsync( - decodedERC721AssetData.tokenAddress, - decodedERC721AssetData.tokenId, - { - defaultBlock: this._stateLayer, - }, - ); - balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0); - break; - case AssetProxyId.MultiAsset: - // The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`. - for (const [ - index, + }, + ); + balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + // The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`. + for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { + const nestedAmountElement = decodedAssetData.amounts[index]; + const nestedAssetBalance = (await this.getBalanceAsync( nestedAssetDataElement, - ] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) { - const nestedAmountElement = (decodedAssetData as MultiAssetData).amounts[index]; - const nestedAssetBalance = (await this.getBalanceAsync( - nestedAssetDataElement, - userAddress, - )).dividedToIntegerBy(nestedAmountElement); - if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) { - balance = nestedAssetBalance; - } + userAddress, + )).dividedToIntegerBy(nestedAmountElement); + if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) { + balance = nestedAssetBalance; } - break; - default: - throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`); + } } return balance as BigNumber; } public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> { const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); let proxyAllowance: BigNumber | undefined; - switch (decodedAssetData.assetProxyId) { - case AssetProxyId.ERC20: - const decodedERC20AssetData = decodedAssetData as ERC20AssetData; - proxyAllowance = await this._erc20Token.getProxyAllowanceAsync( - decodedERC20AssetData.tokenAddress, - userAddress, - { - defaultBlock: this._stateLayer, - }, - ); - break; - case AssetProxyId.ERC721: - const decodedERC721AssetData = decodedAssetData as ERC721AssetData; - const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync( - decodedERC721AssetData.tokenAddress, - userAddress, + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(decodedAssetData.tokenAddress, userAddress, { + defaultBlock: this._stateLayer, + }); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync( + decodedAssetData.tokenAddress, + userAddress, + { + defaultBlock: this._stateLayer, + }, + ); + if (isApprovedForAll) { + return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + } else { + const isApproved = await this._erc721Token.isProxyApprovedAsync( + decodedAssetData.tokenAddress, + decodedAssetData.tokenId, { defaultBlock: this._stateLayer, }, ); - if (isApprovedForAll) { - return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - } else { - const isApproved = await this._erc721Token.isProxyApprovedAsync( - decodedERC721AssetData.tokenAddress, - decodedERC721AssetData.tokenId, - { - defaultBlock: this._stateLayer, - }, - ); - proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0); - } - break; - case AssetProxyId.MultiAsset: - // The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`. - for (const [ - index, + proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0); + } + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + // The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`. + for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { + const nestedAmountElement = decodedAssetData.amounts[index]; + const nestedAssetAllowance = (await this.getProxyAllowanceAsync( nestedAssetDataElement, - ] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) { - const nestedAmountElement = (decodedAssetData as MultiAssetData).amounts[index]; - const nestedAssetAllowance = (await this.getProxyAllowanceAsync( - nestedAssetDataElement, - userAddress, - )).dividedToIntegerBy(nestedAmountElement); - if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) { - proxyAllowance = nestedAssetAllowance; - } + userAddress, + )).dividedToIntegerBy(nestedAmountElement); + if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) { + proxyAllowance = nestedAssetAllowance; } - break; - default: - throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`); + } } return proxyAllowance as BigNumber; } diff --git a/packages/fill-scenarios/src/fill_scenarios.ts b/packages/fill-scenarios/src/fill_scenarios.ts index 2e87e60cc..ce1f7f9ff 100644 --- a/packages/fill-scenarios/src/fill_scenarios.ts +++ b/packages/fill-scenarios/src/fill_scenarios.ts @@ -2,14 +2,7 @@ import { DummyERC20TokenContract, DummyERC721TokenContract, ExchangeContract } f import * as artifacts from '@0x/contract-artifacts'; import { assetDataUtils } from '@0x/order-utils'; import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; -import { - AssetProxyId, - ERC20AssetData, - ERC721AssetData, - MultiAssetData, - OrderWithoutExchangeAddress, - SignedOrder, -} from '@0x/types'; +import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; @@ -280,42 +273,24 @@ export class FillScenarios { amount: BigNumber, ): Promise<void> { const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - switch (decodedAssetData.assetProxyId) { - case AssetProxyId.ERC20: - await this._increaseERC20BalanceAndAllowanceAsync( - // tslint:disable-next-line:no-unnecessary-type-assertion - (decodedAssetData as ERC20AssetData).tokenAddress, - userAddress, - amount, - ); - break; - case AssetProxyId.ERC721: - await this._increaseERC721BalanceAndAllowanceAsync( - // tslint:disable-next-line:no-unnecessary-type-assertion - (decodedAssetData as ERC721AssetData).tokenAddress, + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + await this._increaseERC20BalanceAndAllowanceAsync(decodedAssetData.tokenAddress, userAddress, amount); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + await this._increaseERC721BalanceAndAllowanceAsync( + decodedAssetData.tokenAddress, + userAddress, + decodedAssetData.tokenId, + ); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { + const amountsElement = decodedAssetData.amounts[index]; + const totalAmount = amount.times(amountsElement); + await this._increaseBalanceAndAllowanceWithAssetDataAsync( + nestedAssetDataElement, userAddress, - // tslint:disable-next-line:no-unnecessary-type-assertion - (decodedAssetData as ERC721AssetData).tokenId, + totalAmount, ); - break; - case AssetProxyId.MultiAsset: - for (const [ - index, - nestedAssetDataElement, - // tslint:disable-next-line:no-unnecessary-type-assertion - ] of (decodedAssetData as MultiAssetData).nestedAssetData.entries()) { - // tslint:disable-next-line:no-unnecessary-type-assertion - const amountsElement = (decodedAssetData as MultiAssetData).amounts[index]; - const totalAmount = amount.times(amountsElement); - await this._increaseBalanceAndAllowanceWithAssetDataAsync( - nestedAssetDataElement, - userAddress, - totalAmount, - ); - } - break; - default: - throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`); + } } } } diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index c2929d426..0526c3d00 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -7,7 +7,6 @@ import { SingleAssetData, } from '@0x/types'; import { AbiEncoder, BigNumber } from '@0x/utils'; -import { MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; import { constants } from './constants'; @@ -23,7 +22,7 @@ export const assetDataUtils = { * @return The hex encoded assetData string */ encodeERC20AssetData(tokenAddress: string): string { - const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI); const args = [tokenAddress]; const assetData = abiEncoder.encode(args, encodingRules); return assetData; @@ -36,7 +35,7 @@ export const assetDataUtils = { decodeERC20AssetData(assetData: string): ERC20AssetData { assetDataUtils.assertIsERC20AssetData(assetData); const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); - const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI); const decodedAssetData = abiEncoder.decode(assetData, decodingRules); return { assetProxyId, @@ -52,7 +51,7 @@ export const assetDataUtils = { * @return The hex encoded assetData string */ encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { - const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI); const args = [tokenAddress, tokenId]; const assetData = abiEncoder.encode(args, encodingRules); return assetData; @@ -65,7 +64,7 @@ export const assetDataUtils = { decodeERC721AssetData(assetData: string): ERC721AssetData { assetDataUtils.assertIsERC721AssetData(assetData); const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); - const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI); const decodedAssetData = abiEncoder.decode(assetData, decodingRules); return { assetProxyId, @@ -90,7 +89,7 @@ export const assetDataUtils = { ); } _.forEach(nestedAssetData, assetDataElement => assetDataUtils.validateAssetDataOrThrow(assetDataElement)); - const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI); const args = [amounts, nestedAssetData]; const assetData = abiEncoder.encode(args, encodingRules); return assetData; @@ -103,7 +102,7 @@ export const assetDataUtils = { decodeMultiAssetData(assetData: string): MultiAssetData { assetDataUtils.assertIsMultiAssetData(assetData); const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); - const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI as MethodAbi); + const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI); const decodedAssetData = abiEncoder.decode(assetData, decodingRules); // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion const amounts = (decodedAssetData as any).amounts; @@ -138,7 +137,7 @@ export const assetDataUtils = { nestedAssetDataElement, ); amounts.push( - _.map(recursivelyDecodedAssetData.amounts as BigNumber[], amountElement => + _.map(recursivelyDecodedAssetData.amounts, amountElement => amountElement.times(decodedAssetData.amounts[index]), ), ); @@ -182,6 +181,27 @@ export const assetDataUtils = { return assetProxyId; }, /** + * Checks if the decoded asset data is valid ERC20 data + * @param decodedAssetData The decoded asset data to check + */ + isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC20AssetData { + return decodedAssetData.assetProxyId === AssetProxyId.ERC20; + }, + /** + * Checks if the decoded asset data is valid ERC721 data + * @param decodedAssetData The decoded asset data to check + */ + isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData { + return decodedAssetData.assetProxyId === AssetProxyId.ERC721; + }, + /** + * Checks if the decoded asset data is valid MultiAsset data + * @param decodedAssetData The decoded asset data to check + */ + isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData { + return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; + }, + /** * Throws if the length or assetProxyId are invalid for the ERC20Proxy. * @param assetData Hex encoded assetData string */ diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts index 1248a5576..a9a687719 100644 --- a/packages/order-utils/src/constants.ts +++ b/packages/order-utils/src/constants.ts @@ -1,4 +1,58 @@ import { BigNumber } from '@0x/utils'; +import { MethodAbi } from 'ethereum-types'; + +const ERC20_METHOD_ABI: MethodAbi = { + constant: false, + inputs: [ + { + name: 'tokenContract', + type: 'address', + }, + ], + name: 'ERC20Token', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +}; + +const ERC721_METHOD_ABI: MethodAbi = { + constant: false, + inputs: [ + { + name: 'tokenContract', + type: 'address', + }, + { + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'ERC721Token', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +}; + +const MULTI_ASSET_METHOD_ABI: MethodAbi = { + constant: false, + inputs: [ + { + name: 'amounts', + type: 'uint256[]', + }, + { + name: 'nestedAssetData', + type: 'bytes[]', + }, + ], + name: 'MultiAsset', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +}; export const constants = { NULL_ADDRESS: '0x0000000000000000000000000000000000000000', @@ -49,54 +103,7 @@ export const constants = { { name: 'data', type: 'bytes' }, ], }, - ERC20_METHOD_ABI: { - constant: false, - inputs: [ - { - name: 'tokenContract', - type: 'address', - }, - ], - name: 'ERC20Token', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - ERC721_METHOD_ABI: { - constant: false, - inputs: [ - { - name: 'tokenContract', - type: 'address', - }, - { - name: 'tokenId', - type: 'uint256', - }, - ], - name: 'ERC721Token', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - MULTI_ASSET_METHOD_ABI: { - constant: false, - inputs: [ - { - name: 'amounts', - type: 'uint256[]', - }, - { - name: 'nestedAssetData', - type: 'bytes[]', - }, - ], - name: 'MultiAsset', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, + ERC20_METHOD_ABI, + ERC721_METHOD_ABI, + MULTI_ASSET_METHOD_ABI, }; diff --git a/packages/order-utils/src/exchange_transfer_simulator.ts b/packages/order-utils/src/exchange_transfer_simulator.ts index 0a948fd1f..06621fd9e 100644 --- a/packages/order-utils/src/exchange_transfer_simulator.ts +++ b/packages/order-utils/src/exchange_transfer_simulator.ts @@ -108,7 +108,7 @@ export class ExchangeTransferSimulator { const amountsElement = decodedAssetData.amounts[index]; const totalAmount = amountInBaseUnits.times(amountsElement); await this.transferFromAsync( - nestedAssetDataElement as string, + nestedAssetDataElement, from, to, totalAmount, diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts index 9e3e228ba..389419587 100644 --- a/packages/order-utils/src/order_state_utils.ts +++ b/packages/order-utils/src/order_state_utils.ts @@ -1,14 +1,11 @@ import { - AssetProxyId, ExchangeContractErrs, - MultiAssetData, ObjectMap, OrderRelevantState, OrderState, OrderStateInvalid, OrderStateValid, SignedOrder, - SingleAssetData, } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; @@ -310,22 +307,16 @@ export class OrderStateUtils { ): Promise<ObjectMap<BigNumber>> { const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); let balances: ObjectMap<BigNumber> = { ...initialBalances }; - switch (decodedAssetData.assetProxyId) { - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: - const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); - const tokenAddress = (decodedAssetData as SingleAssetData).tokenAddress; - balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress]) - ? balance - : balances[tokenAddress].add(balance); - break; - case AssetProxyId.MultiAsset: - for (const assetDataElement of (decodedAssetData as MultiAssetData).nestedAssetData) { - balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances); - } - break; - default: - throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`); + if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) { + const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); + const tokenAddress = decodedAssetData.tokenAddress; + balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress]) + ? balance + : balances[tokenAddress].add(balance); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + for (const assetDataElement of decodedAssetData.nestedAssetData) { + balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances); + } } return balances; } @@ -336,25 +327,19 @@ export class OrderStateUtils { ): Promise<ObjectMap<BigNumber>> { const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); let allowances: ObjectMap<BigNumber> = { ...initialAllowances }; - switch (decodedAssetData.assetProxyId) { - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: - const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - traderAddress, - ); - const tokenAddress = (decodedAssetData as SingleAssetData).tokenAddress; - allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress]) - ? allowance - : allowances[tokenAddress].add(allowance); - break; - case AssetProxyId.MultiAsset: - for (const assetDataElement of (decodedAssetData as MultiAssetData).nestedAssetData) { - allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances); - } - break; - default: - throw new Error(`Proxy with id ${decodedAssetData.assetProxyId} not supported`); + if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) { + const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( + assetData, + traderAddress, + ); + const tokenAddress = decodedAssetData.tokenAddress; + allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress]) + ? allowance + : allowances[tokenAddress].add(allowance); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + for (const assetDataElement of decodedAssetData.nestedAssetData) { + allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances); + } } return allowances; } diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts index ebc5bdeac..c498c5a00 100644 --- a/packages/order-utils/test/asset_data_utils_test.ts +++ b/packages/order-utils/test/asset_data_utils_test.ts @@ -27,7 +27,6 @@ const KNOWN_MULTI_ASSET_ENCODING = { '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', }; -// tslint:disable:no-unnecessary-type-assertion describe('assetDataUtils', () => { it('should encode ERC20', () => { const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address); @@ -69,6 +68,7 @@ describe('assetDataUtils', () => { expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); const decodedErc20AssetData = decodedAssetData.nestedAssetData[0]; + // tslint:disable-next-line:no-unnecessary-type-assertion const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData; expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20); @@ -91,8 +91,10 @@ describe('assetDataUtils', () => { const expectedLength = 4; expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedLength); const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[0]; + // tslint:disable-next-line:no-unnecessary-type-assertion const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[1] as ERC721AssetData; const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[2]; + // tslint:disable-next-line:no-unnecessary-type-assertion const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[3] as ERC721AssetData; expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20); 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 12723f73e..d1085014c 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,5 @@ -// tslint:disable:no-unnecessary-type-assertion import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { AssetProxyId, ERC20AssetData, ERC721AssetData, MultiAssetData, SignedOrder } from '@0x/types'; +import { AssetProxyId, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; @@ -70,7 +69,10 @@ export class DependentOrderHashesTracker { 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) { + if ( + assetDataUtils.isERC20AssetData(decodedMakerAssetData) && + decodedMakerAssetData.tokenAddress !== this._zrxTokenAddress + ) { this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); } this._removeFromMakerDependentOrderhashes(signedOrder); @@ -149,24 +151,14 @@ export class DependentOrderHashesTracker { } 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; + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + this._addToERC20DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + this._addToERC721DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress, decodedAssetData.tokenId); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => + this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement), + ); } } private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void { @@ -234,27 +226,18 @@ export class DependentOrderHashesTracker { } 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; + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + this._removeFromERC20DependentOrderhashes(signedOrder, decodedAssetData.tokenAddress); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + this._removeFromERC721DependentOrderhashes( + signedOrder, + decodedAssetData.tokenAddress, + decodedAssetData.tokenId, + ); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => + this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement), + ); } } } diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts index c48606555..656f21a53 100644 --- a/packages/order-watcher/src/order_watcher/order_watcher.ts +++ b/packages/order-watcher/src/order_watcher/order_watcher.ts @@ -32,16 +32,7 @@ import { orderHashUtils, OrderStateUtils, } from '@0x/order-utils'; -import { - AssetProxyId, - ERC20AssetData, - ERC721AssetData, - ExchangeContractErrs, - MultiAssetData, - OrderState, - SignedOrder, - Stats, -} from '@0x/types'; +import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder, Stats } from '@0x/types'; import { errorUtils, intervalUtils } from '@0x/utils'; import { BlockParamLiteral, LogEntryEvent, LogWithDecodedArgs, Provider } from 'ethereum-types'; import * as _ from 'lodash'; @@ -240,20 +231,14 @@ export class OrderWatcher { } 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; + if (assetDataUtils.isERC20AssetData(decodedAssetData)) { + this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress); + } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { + this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress); + } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { + _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => + this._addAssetDataToAbiDecoder(nestedAssetDataElement), + ); } } private _deleteLazyStoreBalance(assetData: string, userAddress: string): void { diff --git a/packages/pipeline/src/parsers/events/exchange_events.ts b/packages/pipeline/src/parsers/events/exchange_events.ts index 8d2e7dec7..9c4a5f89a 100644 --- a/packages/pipeline/src/parsers/events/exchange_events.ts +++ b/packages/pipeline/src/parsers/events/exchange_events.ts @@ -1,14 +1,12 @@ import { ExchangeCancelEventArgs, ExchangeCancelUpToEventArgs, ExchangeFillEventArgs } from '@0x/contract-wrappers'; import { assetDataUtils } from '@0x/order-utils'; -import { AssetProxyId, ERC721AssetData, SingleAssetData } from '@0x/types'; +import { AssetProxyId, ERC721AssetData } from '@0x/types'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as R from 'ramda'; import { ExchangeCancelEvent, ExchangeCancelUpToEvent, ExchangeFillEvent } from '../../entities'; import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils'; -// tslint:disable:no-unnecessary-type-assertion - /** * Parses raw event logs for a fill event and returns an array of * ExchangeFillEvent entities. @@ -59,26 +57,24 @@ export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<Exchang exchangeFillEvent.takerFeePaid = eventLog.args.takerFeePaid; exchangeFillEvent.orderHash = eventLog.args.orderHash; exchangeFillEvent.rawMakerAssetData = eventLog.args.makerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion exchangeFillEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId); exchangeFillEvent.makerAssetProxyId = makerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - exchangeFillEvent.makerTokenAddress = - makerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0] - .tokenAddress - : (makerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + exchangeFillEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress + : makerAssetData.tokenAddress; // tslint has a false positive here. Type assertion is required. // tslint:disable-next-line:no-unnecessary-type-assertion exchangeFillEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId); exchangeFillEvent.rawTakerAssetData = eventLog.args.takerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion exchangeFillEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId); exchangeFillEvent.takerAssetProxyId = takerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - exchangeFillEvent.takerTokenAddress = - takerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0] - .tokenAddress - : (takerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + exchangeFillEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress + : takerAssetData.tokenAddress; // tslint:disable-next-line:no-unnecessary-type-assertion exchangeFillEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId); return exchangeFillEvent; @@ -106,25 +102,23 @@ export function _convertToExchangeCancelEvent( exchangeCancelEvent.senderAddress = eventLog.args.senderAddress; exchangeCancelEvent.orderHash = eventLog.args.orderHash; exchangeCancelEvent.rawMakerAssetData = eventLog.args.makerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion exchangeCancelEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId); exchangeCancelEvent.makerAssetProxyId = makerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - exchangeCancelEvent.makerTokenAddress = - makerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0] - .tokenAddress - : (makerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + exchangeCancelEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress + : makerAssetData.tokenAddress; // tslint:disable-next-line:no-unnecessary-type-assertion exchangeCancelEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId); exchangeCancelEvent.rawTakerAssetData = eventLog.args.takerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion exchangeCancelEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId); exchangeCancelEvent.takerAssetProxyId = takerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - exchangeCancelEvent.takerTokenAddress = - takerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0] - .tokenAddress - : (takerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + exchangeCancelEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress + : takerAssetData.tokenAddress; // tslint:disable-next-line:no-unnecessary-type-assertion exchangeCancelEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId); return exchangeCancelEvent; diff --git a/packages/pipeline/src/parsers/sra_orders/index.ts b/packages/pipeline/src/parsers/sra_orders/index.ts index 10546921d..13fe632a4 100644 --- a/packages/pipeline/src/parsers/sra_orders/index.ts +++ b/packages/pipeline/src/parsers/sra_orders/index.ts @@ -1,13 +1,11 @@ import { APIOrder, OrdersResponse } from '@0x/connect'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { AssetProxyId, ERC721AssetData, SingleAssetData } from '@0x/types'; +import { AssetProxyId, ERC721AssetData } from '@0x/types'; import * as R from 'ramda'; import { SraOrder } from '../../entities'; import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils'; -// tslint:disable:no-unnecessary-type-assertion - /** * Parses a raw order response from an SRA endpoint and returns an array of * SraOrder entities. @@ -43,26 +41,24 @@ export function _convertToEntity(apiOrder: APIOrder): SraOrder { sraOrder.signature = apiOrder.order.signature; sraOrder.rawMakerAssetData = apiOrder.order.makerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion sraOrder.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId); sraOrder.makerAssetProxyId = makerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - sraOrder.makerTokenAddress = - makerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.makerAssetData).nestedAssetData[0] - .tokenAddress - : (makerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + sraOrder.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.makerAssetData).nestedAssetData[0].tokenAddress + : makerAssetData.tokenAddress; // tslint has a false positive here. Type assertion is required. // tslint:disable-next-line:no-unnecessary-type-assertion sraOrder.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId); sraOrder.rawTakerAssetData = apiOrder.order.takerAssetData; + // tslint:disable-next-line:no-unnecessary-type-assertion sraOrder.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId); sraOrder.takerAssetProxyId = takerAssetData.assetProxyId; - // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store a null byte array when decoding assetData from the MultiAssetProxy - sraOrder.takerTokenAddress = - takerAssetData.assetProxyId === AssetProxyId.MultiAsset - ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.takerAssetData).nestedAssetData[0] - .tokenAddress - : (takerAssetData as SingleAssetData).tokenAddress; + // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData + sraOrder.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData) + ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.takerAssetData).nestedAssetData[0].tokenAddress + : takerAssetData.tokenAddress; // tslint:disable-next-line:no-unnecessary-type-assertion sraOrder.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId); |