From e617da3bbf650b25c29df33cd12e23c994efe674 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 6 Jun 2018 22:13:50 +0200 Subject: Implement initial generateOrder function that given the scenario values for an order, generates the actual order. --- .../contracts/src/utils/combinatorial_utils.ts | 213 +++++++++++++++++++++ packages/contracts/src/utils/types.ts | 31 +++ 2 files changed, 244 insertions(+) create mode 100644 packages/contracts/src/utils/combinatorial_utils.ts (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/combinatorial_utils.ts b/packages/contracts/src/utils/combinatorial_utils.ts new file mode 100644 index 000000000..c7d48c86d --- /dev/null +++ b/packages/contracts/src/utils/combinatorial_utils.ts @@ -0,0 +1,213 @@ +import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { Order } from '@0xproject/types'; +import { BigNumber, errorUtils } from '@0xproject/utils'; + +import { constants } from './constants'; +import { + AssetDataScenario, + ERC721Token, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + OrderAmountScenario, +} from './types'; + +const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); +const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); +const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); +const ONE_NFT_UNIT = new BigNumber(1); +const TEN_MINUTES_MS = 1000 * 60 * 10; + +export const combinatorialUtils = { + generateOrder( + userAddresses: string[], + zrxAddress: string, + nonZrxERC20EighteenDecimalTokenAddress: string, + erc20FiveDecimalTokenAddress: string, + erc721Token: ERC721Token, + exchangeAddress: string, + feeRecipientScenario: FeeRecipientAddressScenario, + makerAssetAmountScenario: OrderAmountScenario, + takerAssetAmountScenario: OrderAmountScenario, + makerFeeScenario: OrderAmountScenario, + takerFeeScenario: OrderAmountScenario, + expirationTimeSecondsScenario: ExpirationTimeSecondsScenario, + makerAssetDataScenario: AssetDataScenario, + takerAssetDataScenario: AssetDataScenario, + ): Order { + let feeRecipientAddress; + let makerAssetAmount; + let takerAssetAmount; + let makerFee; + let takerFee; + let expirationTimeSeconds; + let makerAssetData; + let takerAssetData; + + switch (feeRecipientScenario) { + case FeeRecipientAddressScenario.BurnAddress: + feeRecipientAddress = constants.NULL_ADDRESS; + break; + case FeeRecipientAddressScenario.EthUserAddress: + feeRecipientAddress = userAddresses[4]; + break; + default: + throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', feeRecipientScenario); + } + + const invalidAssetProxyIdHex = '0A'; + switch (makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + makerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress); + break; + case AssetDataScenario.ERC20InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); + makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + case AssetDataScenario.ERC721ValidAssetProxyId: + makerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); + break; + case AssetDataScenario.ERC721InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); + makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + } + + switch (takerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + takerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + takerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress); + break; + case AssetDataScenario.ERC20InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); + takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + case AssetDataScenario.ERC721ValidAssetProxyId: + takerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); + break; + case AssetDataScenario.ERC721InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); + takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + } + + switch (makerAssetAmountScenario) { + case OrderAmountScenario.NonZero: + switch (makerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ERC20InvalidAssetProxyId: + makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721ValidAssetProxyId: + case AssetDataScenario.ERC721InvalidAssetProxyId: + makerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + } + break; + case OrderAmountScenario.Zero: + makerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerAssetAmountScenario); + } + + switch (takerAssetAmountScenario) { + case OrderAmountScenario.NonZero: + switch (takerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ERC20InvalidAssetProxyId: + takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721ValidAssetProxyId: + case AssetDataScenario.ERC721InvalidAssetProxyId: + takerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + } + break; + case OrderAmountScenario.Zero: + takerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerAssetAmountScenario); + } + + switch (makerFeeScenario) { + case OrderAmountScenario.NonZero: + makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAmountScenario.Zero: + makerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerFeeScenario); + } + + switch (takerFeeScenario) { + case OrderAmountScenario.NonZero: + takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAmountScenario.Zero: + takerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerFeeScenario); + } + + switch (expirationTimeSecondsScenario) { + case ExpirationTimeSecondsScenario.InFuture: + expirationTimeSeconds = new BigNumber(Date.now() + TEN_MINUTES_MS); + break; + case ExpirationTimeSecondsScenario.InPast: + expirationTimeSeconds = new BigNumber(Date.now() - TEN_MINUTES_MS); + break; + default: + throw errorUtils.spawnSwitchErr('ExpirationTimeSecondsScenario', expirationTimeSecondsScenario); + } + + const order: Order = { + senderAddress: constants.NULL_ADDRESS, + makerAddress: userAddresses[1], + takerAddress: userAddresses[2], + makerFee, + takerFee, + makerAssetAmount, + takerAssetAmount, + makerAssetData, + takerAssetData, + salt: generatePseudoRandomSalt(), + exchangeAddress, + feeRecipientAddress, + expirationTimeSeconds, + }; + + return order; + }, +}; diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 360e1fdbc..58d855c04 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -147,3 +147,34 @@ export interface MatchOrder { leftSignature: string; rightSignature: string; } + +export interface ERC721Token { + address: string; + id: BigNumber; +} + +// Combinatorial testing types + +export enum FeeRecipientAddressScenario { + BurnAddress = 'BURN_ADDRESS', + EthUserAddress = 'ETH_USER_ADDRESS', +} + +export enum OrderAmountScenario { + Zero = 'ZERO', + NonZero = 'NON_ZERO', +} + +export enum ExpirationTimeSecondsScenario { + InPast = 'IN_PAST', + InFuture = 'IN_FUTURE', +} + +export enum AssetDataScenario { + ERC721ValidAssetProxyId = 'ERC721_VALID_ASSET_PROXY_ID', + ERC721InvalidAssetProxyId = 'ERC721_INVALID_ASSET_PROXY_ID', + ZRXFeeToken = 'ZRX_FEE_TOKEN', + ERC20InvalidAssetProxyId = 'ERC20_INVALID_ASSET_PROXY_ID', + ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', + ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', +} -- cgit v1.2.3 From ab5e021bda5cc8e39d8595580c09c3540a09aff5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 7 Jun 2018 18:00:13 +0200 Subject: POC: Generates an order from spec, get's the amount fillable --- .../contracts/src/utils/combinatorial_utils.ts | 213 ----------------- packages/contracts/src/utils/erc20_wrapper.ts | 28 ++- packages/contracts/src/utils/new_order_factory.ts | 264 +++++++++++++++++++++ packages/contracts/src/utils/order_info_utils.ts | 44 ++++ .../simple_erc20_balance_and_allowance_fetcher.ts | 20 ++ .../src/utils/simple_filled_cancelled_fetcher.ts | 32 +++ packages/contracts/src/utils/types.ts | 5 - 7 files changed, 385 insertions(+), 221 deletions(-) delete mode 100644 packages/contracts/src/utils/combinatorial_utils.ts create mode 100644 packages/contracts/src/utils/new_order_factory.ts create mode 100644 packages/contracts/src/utils/order_info_utils.ts create mode 100644 packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts create mode 100644 packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/combinatorial_utils.ts b/packages/contracts/src/utils/combinatorial_utils.ts deleted file mode 100644 index c7d48c86d..000000000 --- a/packages/contracts/src/utils/combinatorial_utils.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; -import { Order } from '@0xproject/types'; -import { BigNumber, errorUtils } from '@0xproject/utils'; - -import { constants } from './constants'; -import { - AssetDataScenario, - ERC721Token, - ExpirationTimeSecondsScenario, - FeeRecipientAddressScenario, - OrderAmountScenario, -} from './types'; - -const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); -const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); -const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); -const ONE_NFT_UNIT = new BigNumber(1); -const TEN_MINUTES_MS = 1000 * 60 * 10; - -export const combinatorialUtils = { - generateOrder( - userAddresses: string[], - zrxAddress: string, - nonZrxERC20EighteenDecimalTokenAddress: string, - erc20FiveDecimalTokenAddress: string, - erc721Token: ERC721Token, - exchangeAddress: string, - feeRecipientScenario: FeeRecipientAddressScenario, - makerAssetAmountScenario: OrderAmountScenario, - takerAssetAmountScenario: OrderAmountScenario, - makerFeeScenario: OrderAmountScenario, - takerFeeScenario: OrderAmountScenario, - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario, - makerAssetDataScenario: AssetDataScenario, - takerAssetDataScenario: AssetDataScenario, - ): Order { - let feeRecipientAddress; - let makerAssetAmount; - let takerAssetAmount; - let makerFee; - let takerFee; - let expirationTimeSeconds; - let makerAssetData; - let takerAssetData; - - switch (feeRecipientScenario) { - case FeeRecipientAddressScenario.BurnAddress: - feeRecipientAddress = constants.NULL_ADDRESS; - break; - case FeeRecipientAddressScenario.EthUserAddress: - feeRecipientAddress = userAddresses[4]; - break; - default: - throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', feeRecipientScenario); - } - - const invalidAssetProxyIdHex = '0A'; - switch (makerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - makerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress); - break; - case AssetDataScenario.ERC20InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); - makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - case AssetDataScenario.ERC721ValidAssetProxyId: - makerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); - break; - case AssetDataScenario.ERC721InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); - makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); - } - - switch (takerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - takerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - takerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress); - break; - case AssetDataScenario.ERC20InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress); - takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - case AssetDataScenario.ERC721ValidAssetProxyId: - takerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); - break; - case AssetDataScenario.ERC721InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id); - takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); - } - - switch (makerAssetAmountScenario) { - case OrderAmountScenario.NonZero: - switch (makerAssetDataScenario) { - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ERC20InvalidAssetProxyId: - makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721ValidAssetProxyId: - case AssetDataScenario.ERC721InvalidAssetProxyId: - makerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); - } - break; - case OrderAmountScenario.Zero: - makerAssetAmount = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerAssetAmountScenario); - } - - switch (takerAssetAmountScenario) { - case OrderAmountScenario.NonZero: - switch (takerAssetDataScenario) { - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ERC20InvalidAssetProxyId: - takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721ValidAssetProxyId: - case AssetDataScenario.ERC721InvalidAssetProxyId: - takerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); - } - break; - case OrderAmountScenario.Zero: - takerAssetAmount = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerAssetAmountScenario); - } - - switch (makerFeeScenario) { - case OrderAmountScenario.NonZero: - makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAmountScenario.Zero: - makerFee = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerFeeScenario); - } - - switch (takerFeeScenario) { - case OrderAmountScenario.NonZero: - takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAmountScenario.Zero: - takerFee = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerFeeScenario); - } - - switch (expirationTimeSecondsScenario) { - case ExpirationTimeSecondsScenario.InFuture: - expirationTimeSeconds = new BigNumber(Date.now() + TEN_MINUTES_MS); - break; - case ExpirationTimeSecondsScenario.InPast: - expirationTimeSeconds = new BigNumber(Date.now() - TEN_MINUTES_MS); - break; - default: - throw errorUtils.spawnSwitchErr('ExpirationTimeSecondsScenario', expirationTimeSecondsScenario); - } - - const order: Order = { - senderAddress: constants.NULL_ADDRESS, - makerAddress: userAddresses[1], - takerAddress: userAddresses[2], - makerFee, - takerFee, - makerAssetAmount, - takerAssetAmount, - makerAssetData, - takerAssetData, - salt: generatePseudoRandomSalt(), - exchangeAddress, - feeRecipientAddress, - expirationTimeSeconds, - }; - - return order; - }, -}; diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index dceeceeea..efb245c89 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -25,8 +25,11 @@ export class ERC20Wrapper { this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; } - public async deployDummyTokensAsync(): Promise { - for (let i = 0; i < constants.NUM_DUMMY_ERC20_TO_DEPLOY; i++) { + public async deployDummyTokensAsync(num?: number, decimals?: BigNumber): Promise { + // TODO(fabio): Remove and refactor all tests + const finalNum = _.isUndefined(num) ? constants.NUM_DUMMY_ERC20_TO_DEPLOY : num; + const finalDecimals = _.isUndefined(decimals) ? constants.DUMMY_TOKEN_DECIMALS : decimals; + for (let i = 0; i < finalNum; i++) { this._dummyTokenContracts.push( await DummyERC20TokenContract.deployFrom0xArtifactAsync( artifacts.DummyERC20Token, @@ -34,7 +37,7 @@ export class ERC20Wrapper { txDefaults, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, + finalDecimals, constants.DUMMY_TOKEN_TOTAL_SUPPLY, ), ); @@ -73,6 +76,25 @@ export class ERC20Wrapper { } } } + public async getBalanceAsync(owner: string, token: string): Promise { + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`); + } + const balance = new BigNumber(await tokenContractIfExists.balanceOf.callAsync(owner)); + return balance; + } + public async getProxyAllowanceAsync(owner: string, token: string): Promise { + this._validateProxyContractExistsOrThrow(); + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`); + } + const balance = new BigNumber( + await tokenContractIfExists.allowance.callAsync(owner, (this._proxyContract as ERC20ProxyContract).address), + ); + return balance; + } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); const balancesByOwner: ERC20BalancesByOwner = {}; diff --git a/packages/contracts/src/utils/new_order_factory.ts b/packages/contracts/src/utils/new_order_factory.ts new file mode 100644 index 000000000..a4ded4230 --- /dev/null +++ b/packages/contracts/src/utils/new_order_factory.ts @@ -0,0 +1,264 @@ +import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { Order } from '@0xproject/types'; +import { BigNumber, errorUtils } from '@0xproject/utils'; + +import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token'; + +import { constants } from './constants'; +import { + AssetDataScenario, + ERC721TokenIdsByOwner, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + OrderAmountScenario, +} from './types'; + +const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); +const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); +const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); +const ONE_NFT_UNIT = new BigNumber(1); +const TEN_MINUTES_MS = 1000 * 60 * 10; + +/* + * TODO: + * - Write function that given an order, fillAmount, retrieves orderRelevantState and maps it to expected test outcome. + * - Write function that generates order permutations. + * - Write functions for other steps that must be permutated + */ + +export class NewOrderFactory { + private _userAddresses: string[]; + private _zrxAddress: string; + private _nonZrxERC20EighteenDecimalTokenAddresses: string[]; + private _erc20FiveDecimalTokenAddresses: string[]; + private _erc721Token: DummyERC721TokenContract; + private _erc721Balances: ERC721TokenIdsByOwner; + private _exchangeAddress: string; + constructor( + userAddresses: string[], + zrxAddress: string, + nonZrxERC20EighteenDecimalTokenAddresses: string[], + erc20FiveDecimalTokenAddresses: string[], + erc721Token: DummyERC721TokenContract, + erc721Balances: ERC721TokenIdsByOwner, + exchangeAddress: string, + ) { + this._userAddresses = userAddresses; + this._zrxAddress = zrxAddress; + this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses; + this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses; + this._erc721Token = erc721Token; + this._erc721Balances = erc721Balances; + this._exchangeAddress = exchangeAddress; + } + public generateOrder( + feeRecipientScenario: FeeRecipientAddressScenario, + makerAssetAmountScenario: OrderAmountScenario, + takerAssetAmountScenario: OrderAmountScenario, + makerFeeScenario: OrderAmountScenario, + takerFeeScenario: OrderAmountScenario, + expirationTimeSecondsScenario: ExpirationTimeSecondsScenario, + makerAssetDataScenario: AssetDataScenario, + takerAssetDataScenario: AssetDataScenario, + ): Order { + const makerAddress = this._userAddresses[1]; + const takerAddress = this._userAddresses[2]; + const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address]; + const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address]; + let feeRecipientAddress; + let makerAssetAmount; + let takerAssetAmount; + let makerFee; + let takerFee; + let expirationTimeSeconds; + let makerAssetData; + let takerAssetData; + + switch (feeRecipientScenario) { + case FeeRecipientAddressScenario.BurnAddress: + feeRecipientAddress = constants.NULL_ADDRESS; + break; + case FeeRecipientAddressScenario.EthUserAddress: + feeRecipientAddress = this._userAddresses[4]; + break; + default: + throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', feeRecipientScenario); + } + + const invalidAssetProxyIdHex = '0A'; + switch (makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetData = assetProxyUtils.encodeERC20ProxyData( + this._nonZrxERC20EighteenDecimalTokenAddresses[0], + ); + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[0]); + break; + case AssetDataScenario.ERC20InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC20ProxyData( + this._nonZrxERC20EighteenDecimalTokenAddresses[0], + ); + makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + case AssetDataScenario.ERC721ValidAssetProxyId: + makerAssetData = assetProxyUtils.encodeERC721ProxyData( + this._erc721Token.address, + erc721MakerAssetIds[0], + ); + break; + case AssetDataScenario.ERC721InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC721ProxyData( + this._erc721Token.address, + erc721MakerAssetIds[0], + ); + makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + } + + switch (takerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + takerAssetData = assetProxyUtils.encodeERC20ProxyData( + this._nonZrxERC20EighteenDecimalTokenAddresses[1], + ); + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[1]); + break; + case AssetDataScenario.ERC20InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC20ProxyData( + this._nonZrxERC20EighteenDecimalTokenAddresses[1], + ); + takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + case AssetDataScenario.ERC721ValidAssetProxyId: + takerAssetData = assetProxyUtils.encodeERC721ProxyData( + this._erc721Token.address, + erc721TakerAssetIds[0], + ); + break; + case AssetDataScenario.ERC721InvalidAssetProxyId: { + const validAssetData = assetProxyUtils.encodeERC721ProxyData( + this._erc721Token.address, + erc721TakerAssetIds[0], + ); + takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; + break; + } + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + } + + switch (makerAssetAmountScenario) { + case OrderAmountScenario.NonZero: + switch (makerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ERC20InvalidAssetProxyId: + makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721ValidAssetProxyId: + case AssetDataScenario.ERC721InvalidAssetProxyId: + makerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + } + break; + case OrderAmountScenario.Zero: + makerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerAssetAmountScenario); + } + + switch (takerAssetAmountScenario) { + case OrderAmountScenario.NonZero: + switch (takerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ERC20InvalidAssetProxyId: + takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721ValidAssetProxyId: + case AssetDataScenario.ERC721InvalidAssetProxyId: + takerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + } + break; + case OrderAmountScenario.Zero: + takerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerAssetAmountScenario); + } + + switch (makerFeeScenario) { + case OrderAmountScenario.NonZero: + makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAmountScenario.Zero: + makerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerFeeScenario); + } + + switch (takerFeeScenario) { + case OrderAmountScenario.NonZero: + takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAmountScenario.Zero: + takerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerFeeScenario); + } + + switch (expirationTimeSecondsScenario) { + case ExpirationTimeSecondsScenario.InFuture: + expirationTimeSeconds = new BigNumber(Date.now() + TEN_MINUTES_MS); + break; + case ExpirationTimeSecondsScenario.InPast: + expirationTimeSeconds = new BigNumber(Date.now() - TEN_MINUTES_MS); + break; + default: + throw errorUtils.spawnSwitchErr('ExpirationTimeSecondsScenario', expirationTimeSecondsScenario); + } + + const order: Order = { + senderAddress: constants.NULL_ADDRESS, + makerAddress, + takerAddress, + makerFee, + takerFee, + makerAssetAmount, + takerAssetAmount, + makerAssetData, + takerAssetData, + salt: generatePseudoRandomSalt(), + exchangeAddress: this._exchangeAddress, + feeRecipientAddress, + expirationTimeSeconds, + }; + + return order; + } +} diff --git a/packages/contracts/src/utils/order_info_utils.ts b/packages/contracts/src/utils/order_info_utils.ts new file mode 100644 index 000000000..9df627da3 --- /dev/null +++ b/packages/contracts/src/utils/order_info_utils.ts @@ -0,0 +1,44 @@ +import { assetProxyUtils, OrderStateUtils } from '@0xproject/order-utils'; +import { SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import { ExchangeContract } from '../contract_wrappers/generated/exchange'; + +import { constants } from './constants'; +import { ERC20Wrapper } from './erc20_wrapper'; +import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './simple_erc20_balance_and_allowance_fetcher'; +import { SimpleOrderFilledCancelledFetcher } from './simple_filled_cancelled_fetcher'; + +export class OrderInfoUtils { + private _orderStateUtils: OrderStateUtils; + private _erc20Wrapper: ERC20Wrapper; + constructor(exchangeContract: ExchangeContract, erc20Wrapper: ERC20Wrapper, zrxAddress: string) { + this._erc20Wrapper = erc20Wrapper; + const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(exchangeContract, zrxAddress); + const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher(erc20Wrapper); + this._orderStateUtils = new OrderStateUtils( + simpleERC20BalanceAndProxyAllowanceFetcher, + simpleOrderFilledCancelledFetcher, + ); + } + public async getFillableTakerAssetAmountAsync(signedOrder: SignedOrder, takerAddress: string): Promise { + const orderRelevantState = await this._orderStateUtils.getOrderRelevantStateAsync(signedOrder); + console.log('orderRelevantState', orderRelevantState); + if (takerAddress === constants.NULL_ADDRESS) { + return orderRelevantState.remainingFillableTakerAssetAmount; + } + const takerAssetData = assetProxyUtils.decodeERC20ProxyData(signedOrder.takerAssetData); + const takerBalance = await this._erc20Wrapper.getBalanceAsync(takerAddress, takerAssetData.tokenAddress); + const takerAllowance = await this._erc20Wrapper.getProxyAllowanceAsync( + takerAddress, + takerAssetData.tokenAddress, + ); + // TODO: We also need to make sure taker has sufficient ZRX for fees... + const fillableTakerAssetAmount = BigNumber.min([ + takerBalance, + takerAllowance, + orderRelevantState.remainingFillableTakerAssetAmount, + ]); + return fillableTakerAssetAmount; + } +} diff --git a/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts b/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts new file mode 100644 index 000000000..6eed9227a --- /dev/null +++ b/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts @@ -0,0 +1,20 @@ +import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; + +import { ERC20Wrapper } from './erc20_wrapper'; + +// TODO(fabio): Refactor this to also work for ERC721! +export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { + private _erc20TokenWrapper: ERC20Wrapper; + constructor(erc20TokenWrapper: ERC20Wrapper) { + this._erc20TokenWrapper = erc20TokenWrapper; + } + public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise { + const balance = await this._erc20TokenWrapper.getBalanceAsync(userAddress, tokenAddress); + return balance; + } + public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise { + const proxyAllowance = await this._erc20TokenWrapper.getProxyAllowanceAsync(userAddress, tokenAddress); + return proxyAllowance; + } +} diff --git a/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts b/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts new file mode 100644 index 000000000..0a80637cc --- /dev/null +++ b/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts @@ -0,0 +1,32 @@ +import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; +import { BlockParamLiteral } from 'ethereum-types'; + +import { + CancelContractEventArgs, + ExchangeContract, + FillContractEventArgs, +} from '../contract_wrappers/generated/exchange'; + +export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { + private _exchangeContract: ExchangeContract; + private _zrxAddress: string; + constructor(exchange: ExchangeContract, zrxAddress: string) { + this._exchangeContract = exchange; + this._zrxAddress = zrxAddress; + } + public async getFilledTakerAmountAsync(orderHash: string): Promise { + const filledTakerAmount = new BigNumber(await this._exchangeContract.filled.callAsync(orderHash)); + return filledTakerAmount; + } + public async isOrderCancelledAsync(orderHash: string): Promise { + const methodOpts = { + defaultBlock: BlockParamLiteral.Latest, + }; + const isCancelled = await this._exchangeContract.cancelled.callAsync(orderHash); + return isCancelled; + } + public getZRXTokenAddress(): string { + return this._zrxAddress; + } +} diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 94c7f627f..64f6400c5 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -148,11 +148,6 @@ export interface MatchOrder { rightSignature: string; } -export interface ERC721Token { - address: string; - id: BigNumber; -} - // Combinatorial testing types export enum FeeRecipientAddressScenario { -- cgit v1.2.3 From 78dcb87a7501e9076570b3ed9de2a43b924299f3 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 13 Jun 2018 13:11:45 +0200 Subject: Variable rename for clarity --- packages/contracts/src/utils/exchange_wrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/exchange_wrapper.ts b/packages/contracts/src/utils/exchange_wrapper.ts index a8ca5183e..1ecabcf64 100644 --- a/packages/contracts/src/utils/exchange_wrapper.ts +++ b/packages/contracts/src/utils/exchange_wrapper.ts @@ -33,8 +33,8 @@ export class ExchangeWrapper { params.signature, { from }, ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); + return txReceipt; } public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise { const params = orderUtils.createCancel(signedOrder); -- cgit v1.2.3 From fe75660e88ed0c37c4f3d461a644bd9305bf6183 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 13 Jun 2018 16:01:01 +0200 Subject: Refactor ERC20 and ERC721 wrappers for V2 and introduce the assetWrapper superset --- packages/contracts/src/utils/asset_wrapper.ts | 32 +++++++++++++++++++++++ packages/contracts/src/utils/erc20_wrapper.ts | 27 ++++++++++++++------ packages/contracts/src/utils/erc721_wrapper.ts | 35 +++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 packages/contracts/src/utils/asset_wrapper.ts (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts new file mode 100644 index 000000000..4c345aa30 --- /dev/null +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -0,0 +1,32 @@ +import { assetProxyUtils } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { AbstractAssetWrapper } from '../abstract/abstract_asset_wrapper'; + +interface ProxyIdToAssetWrappers { + [proxyId: number]: AbstractAssetWrapper; +} + +export class AssetWrapper { + private _proxyIdToAssetWrappers: ProxyIdToAssetWrappers; + constructor(assetWrappers: AbstractAssetWrapper[]) { + this._proxyIdToAssetWrappers = {}; + _.each(assetWrappers, assetWrapper => { + const proxyId = assetWrapper.getProxyId(); + this._proxyIdToAssetWrappers[proxyId] = assetWrapper; + }); + } + public async getBalanceAsync(owner: string, assetData: string): Promise { + const proxyId = assetProxyUtils.decodeAssetDataId(assetData); + const assetWrapper = this._proxyIdToAssetWrappers[proxyId]; + const balance = await assetWrapper.getBalanceAsync(owner, assetData); + return balance; + } + public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { + const proxyId = assetProxyUtils.decodeAssetDataId(assetData); + const assetWrapper = this._proxyIdToAssetWrappers[proxyId]; + const balance = await assetWrapper.getProxyAllowanceAsync(owner, assetData); + return balance; + } +} diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index fc42fbff2..2d367ae1c 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -1,3 +1,4 @@ +import { assetProxyUtils } from '@0xproject/order-utils'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Provider } from 'ethereum-types'; @@ -18,6 +19,7 @@ export class ERC20Wrapper { private _provider: Provider; private _dummyTokenContracts: DummyERC20TokenContract[]; private _proxyContract?: ERC20ProxyContract; + private _proxyIdIfExists?: number; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._dummyTokenContracts = []; this._web3Wrapper = new Web3Wrapper(provider); @@ -50,8 +52,13 @@ export class ERC20Wrapper { this._provider, txDefaults, ); + this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; } + public getProxyId(): number { + this._validateProxyContractExistsOrThrow(); + return this._proxyIdIfExists as number; + } public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); @@ -76,24 +83,28 @@ export class ERC20Wrapper { } } } - public async getBalanceAsync(owner: string, token: string): Promise { - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token); + public async getBalanceAsync(owner: string, assetData: string): Promise { + const erc20ProxyData = assetProxyUtils.decodeERC20AssetData(assetData); + const tokenAddress = erc20ProxyData.tokenAddress; + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`); + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); } const balance = new BigNumber(await tokenContractIfExists.balanceOf.callAsync(owner)); return balance; } - public async getProxyAllowanceAsync(owner: string, token: string): Promise { + public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { + const erc20ProxyData = assetProxyUtils.decodeERC20AssetData(assetData); + const tokenAddress = erc20ProxyData.tokenAddress; this._validateProxyContractExistsOrThrow(); - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token); + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`); + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); } - const balance = new BigNumber( + const allowance = new BigNumber( await tokenContractIfExists.allowance.callAsync(owner, (this._proxyContract as ERC20ProxyContract).address), ); - return balance; + return allowance; } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index b20d9acd2..6a6f10fa7 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -1,4 +1,4 @@ -import { generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Provider } from 'ethereum-types'; @@ -19,6 +19,7 @@ export class ERC721Wrapper { private _provider: Provider; private _dummyTokenContracts: DummyERC721TokenContract[]; private _proxyContract?: ERC721ProxyContract; + private _proxyIdIfExists?: number; private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); @@ -47,8 +48,13 @@ export class ERC721Wrapper { this._provider, txDefaults, ); + this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; } + public getProxyId(): number { + this._validateProxyContractExistsOrThrow(); + return this._proxyIdIfExists as number; + } public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); @@ -85,6 +91,33 @@ export class ERC721Wrapper { } } } + public async getBalanceAsync(owner: string, assetData: string): Promise { + const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + const tokenAddress = erc721ProxyData.tokenAddress; + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); + } + const tokenId = erc721ProxyData.tokenId; + const tokenOwner = await tokenContractIfExists.ownerOf.callAsync(tokenId); + const balance = tokenOwner === owner ? new BigNumber(1) : new BigNumber(0); + return balance; + } + public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { + const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + const tokenAddress = erc721ProxyData.tokenAddress; + this._validateProxyContractExistsOrThrow(); + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); + } + const operator = (this._proxyContract as ERC721ProxyContract).address; + const didApproveAll = await tokenContractIfExists.isApprovedForAll.callAsync(owner, operator); + const tokenId = erc721ProxyData.tokenId; + const allowedAddress = await tokenContractIfExists.getApproved.callAsync(tokenId); + const allowance = allowedAddress === operator || didApproveAll ? new BigNumber(1) : new BigNumber(0); + return allowance; + } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateBalancesAndAllowancesSetOrThrow(); -- cgit v1.2.3 From 61243b418e4d962cd8d8a1d7a49f04510b3c1c7f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 13 Jun 2018 16:09:04 +0200 Subject: Implement initial set of orderFill combinatorial tests --- .../src/utils/core_combinatorial_utils.ts | 445 +++++++++++++++++++++ packages/contracts/src/utils/exchange_wrapper.ts | 4 + packages/contracts/src/utils/new_order_factory.ts | 130 ++---- packages/contracts/src/utils/order_info_utils.ts | 44 -- packages/contracts/src/utils/order_utils.ts | 7 + ...le_asset_balance_and_proxy_allowance_fetcher.ts | 19 + .../simple_erc20_balance_and_allowance_fetcher.ts | 20 - .../src/utils/simple_filled_cancelled_fetcher.ts | 32 -- .../utils/simple_order_filled_cancelled_fetcher.ts | 24 ++ packages/contracts/src/utils/types.ts | 15 +- 10 files changed, 553 insertions(+), 187 deletions(-) create mode 100644 packages/contracts/src/utils/core_combinatorial_utils.ts delete mode 100644 packages/contracts/src/utils/order_info_utils.ts create mode 100644 packages/contracts/src/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts delete mode 100644 packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts delete mode 100644 packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts create mode 100644 packages/contracts/src/utils/simple_order_filled_cancelled_fetcher.ts (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts new file mode 100644 index 000000000..6fbd8304e --- /dev/null +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -0,0 +1,445 @@ +import { + assetProxyUtils, + BalanceAndProxyAllowanceLazyStore, + ExchangeTransferSimulator, + orderHashUtils, + OrderStateUtils, + OrderValidationUtils, +} from '@0xproject/order-utils'; +import { AssetProxyId, Order, SignatureType, SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as chai from 'chai'; +import { BlockParamLiteral, LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; +// import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; +import 'make-promises-safe'; + +import { ExchangeContract, FillContractEventArgs } from '../generated_contract_wrappers/exchange'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { AssetWrapper } from '../utils/asset_wrapper'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; +import { NewOrderFactory } from '../utils/new_order_factory'; +import { orderUtils } from '../utils/order_utils'; +import { signingUtils } from '../utils/signing_utils'; +import { SimpleAssetBalanceAndProxyAllowanceFetcher } from '../utils/simple_asset_balance_and_proxy_allowance_fetcher'; +import { SimpleOrderFilledCancelledFetcher } from '../utils/simple_order_filled_cancelled_fetcher'; +import { + AssetDataScenario, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + OrderAmountScenario, + OrderScenario, +} from '../utils/types'; + +chaiSetup.configure(); +const expect = chai.expect; + +const ERC721_PROXY_ID = 2; + +/** + * Instantiates a new instance of CoreCombinatorialUtils. Since this method has some + * required async setup, a factory method is required. + * @param web3Wrapper Web3Wrapper instance + * @param txDefaults Default Ethereum tx options + * @return CoreCombinatorialUtils instance + */ +export async function coreCombinatorialUtilsFactoryAsync( + web3Wrapper: Web3Wrapper, + txDefaults: Partial, +): Promise { + const userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + const [ownerAddress, makerAddress, takerAddress] = userAddresses; + const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)]; + + const provider = web3Wrapper.getProvider(); + const erc20Wrapper = new ERC20Wrapper(provider, userAddresses, ownerAddress); + const erc721Wrapper = new ERC721Wrapper(provider, userAddresses, ownerAddress); + + const erc20EighteenDecimalTokenCount = 3; + const eighteenDecimals = new BigNumber(18); + const [ + erc20EighteenDecimalTokenA, + erc20EighteenDecimalTokenB, + zrxToken, + ] = await erc20Wrapper.deployDummyTokensAsync(erc20EighteenDecimalTokenCount, eighteenDecimals); + const zrxAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address); + + const erc20FiveDecimalTokenCount = 2; + const fiveDecimals = new BigNumber(18); + const [erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync( + erc20FiveDecimalTokenCount, + fiveDecimals, + ); + const erc20Proxy = await erc20Wrapper.deployProxyAsync(); + await erc20Wrapper.setBalancesAndAllowancesAsync(); + + const [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); + const erc721Proxy = await erc721Wrapper.deployProxyAsync(); + await erc721Wrapper.setBalancesAndAllowancesAsync(); + const erc721Balances = await erc721Wrapper.getBalancesAsync(); + + const assetWrapper = new AssetWrapper([erc20Wrapper, erc721Wrapper]); + + const exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync( + artifacts.Exchange, + provider, + txDefaults, + zrxAssetData, + ); + const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider); + await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, ownerAddress); + await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, ownerAddress); + + await web3Wrapper.awaitTransactionSuccessAsync( + await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, { + from: ownerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, { + from: ownerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + + const orderFactory = new NewOrderFactory( + userAddresses, + zrxToken.address, + [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address], + [erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address], + erc721Token, + erc721Balances, + exchangeContract.address, + ); + + const coreCombinatorialUtils = new CoreCombinatorialUtils( + orderFactory, + ownerAddress, + makerAddress, + makerPrivateKey, + takerAddress, + zrxAssetData, + exchangeWrapper, + assetWrapper, + ); + return coreCombinatorialUtils; +} + +export class CoreCombinatorialUtils { + public orderFactory: NewOrderFactory; + public ownerAddress: string; + public makerAddress: string; + public makerPrivateKey: Buffer; + public takerAddress: string; + public zrxAssetData: string; + public exchangeWrapper: ExchangeWrapper; + public assetWrapper: AssetWrapper; + public static generateOrderCombinations(): OrderScenario[] { + const feeRecipientScenarios = [FeeRecipientAddressScenario.EthUserAddress]; + const makerAssetAmountScenario = [OrderAmountScenario.NonZero]; + const takerAssetAmountScenario = [OrderAmountScenario.NonZero]; + const makerFeeScenario = [OrderAmountScenario.NonZero]; + const takerFeeScenario = [OrderAmountScenario.NonZero]; + const expirationTimeSecondsScenario = [ExpirationTimeSecondsScenario.InFuture]; + const makerAssetDataScenario = [ + AssetDataScenario.ERC20FiveDecimals, + AssetDataScenario.ERC20NonZRXEighteenDecimals, + AssetDataScenario.ERC721, + AssetDataScenario.ZRXFeeToken, + ]; + const takerAssetDataScenario = [ + AssetDataScenario.ERC20FiveDecimals, + AssetDataScenario.ERC20NonZRXEighteenDecimals, + AssetDataScenario.ERC721, + AssetDataScenario.ZRXFeeToken, + ]; + const orderScenarioArrays = CoreCombinatorialUtils._allPossibleCases([ + feeRecipientScenarios, + makerAssetAmountScenario, + takerAssetAmountScenario, + makerFeeScenario, + takerFeeScenario, + expirationTimeSecondsScenario, + makerAssetDataScenario, + takerAssetDataScenario, + ]); + + const orderScenarios = _.map(orderScenarioArrays, orderScenarioArray => { + const orderScenario: OrderScenario = { + feeRecipientScenario: orderScenarioArray[0] as FeeRecipientAddressScenario, + makerAssetAmountScenario: orderScenarioArray[1] as OrderAmountScenario, + takerAssetAmountScenario: orderScenarioArray[2] as OrderAmountScenario, + makerFeeScenario: orderScenarioArray[3] as OrderAmountScenario, + takerFeeScenario: orderScenarioArray[4] as OrderAmountScenario, + expirationTimeSecondsScenario: orderScenarioArray[5] as ExpirationTimeSecondsScenario, + makerAssetDataScenario: orderScenarioArray[6] as AssetDataScenario, + takerAssetDataScenario: orderScenarioArray[7] as AssetDataScenario, + }; + return orderScenario; + }); + + return orderScenarios; + } + private static _allPossibleCases(arrays: string[][]): string[][] { + if (arrays.length === 1) { + const remainingVals = _.map(arrays[0], val => { + return [val]; + }); + return remainingVals; + } else { + const result = []; + const allCasesOfRest = CoreCombinatorialUtils._allPossibleCases(arrays.slice(1)); // recur with the rest of array + // tslint:disable:prefer-for-of + for (let i = 0; i < allCasesOfRest.length; i++) { + for (let j = 0; j < arrays[0].length; j++) { + result.push([arrays[0][j], ...allCasesOfRest[i]]); + } + } + // tslint:enable:prefer-for-of + return result; + } + } + constructor( + orderFactory: NewOrderFactory, + ownerAddress: string, + makerAddress: string, + makerPrivateKey: Buffer, + takerAddress: string, + zrxAssetData: string, + exchangeWrapper: ExchangeWrapper, + assetWrapper: AssetWrapper, + ) { + this.orderFactory = orderFactory; + this.ownerAddress = ownerAddress; + this.makerAddress = makerAddress; + this.makerPrivateKey = makerPrivateKey; + this.takerAddress = takerAddress; + this.zrxAssetData = zrxAssetData; + this.exchangeWrapper = exchangeWrapper; + this.assetWrapper = assetWrapper; + } + public async testFillOrderScenarioAsync(order: Order, provider: Provider): Promise { + // 2. Sign order + const orderHashBuff = orderHashUtils.getOrderHashBuff(order); + const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign); + const signedOrder = { + ...order, + signature: `0x${signature.toString('hex')}`, + }; + + // 3. Permutate the maker and taker balance/allowance scenarios + + // 4. Figure out fill amount OR error + const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper); + const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher( + this.exchangeWrapper, + this.zrxAssetData, + ); + const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); + + const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync( + signedOrder, + this.takerAddress, + ); + + // If order is fillable, decide how much to fill + // TODO: Make this configurable + const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); + const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); + const isEitherAssetERC721 = takerAssetProxyId === ERC721_PROXY_ID || makerAssetProxyId === ERC721_PROXY_ID; + const takerAssetFillAmount = isEitherAssetERC721 + ? fillableTakerAssetAmount + : fillableTakerAssetAmount.div(2).floor(); + + // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts exp? + const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); + const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); + const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); + + let isFillFailureExpected = false; + try { + await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTransferSimulator, + provider, + signedOrder, + takerAssetFillAmount, + this.takerAddress, + this.zrxAssetData, + ); + } catch (err) { + isFillFailureExpected = true; + } + + await this._fillOrderAndAssertOutcomeAsync( + signedOrder, + takerAssetFillAmount, + lazyStore, + isFillFailureExpected, + provider, + ); + } + private async _fillOrderAndAssertOutcomeAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + lazyStore: BalanceAndProxyAllowanceLazyStore, + isFillFailureExpected: boolean, + provider: Provider, + ): Promise { + if (isFillFailureExpected) { + return expectRevertOrAlwaysFailingTransactionAsync( + this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), + ); + } + + const makerAddress = signedOrder.makerAddress; + const makerAssetData = signedOrder.makerAssetData; + const takerAssetData = signedOrder.takerAssetData; + const feeRecipient = signedOrder.feeRecipientAddress; + + const expMakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(makerAssetData, makerAddress); + const expMakerAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress); + const expTakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(takerAssetData, makerAddress); + const expZRXAssetBalanceOfMaker = await lazyStore.getBalanceAsync(this.zrxAssetData, makerAddress); + const expZRXAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(this.zrxAssetData, makerAddress); + const expTakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(takerAssetData, this.takerAddress); + const expTakerAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress); + const expMakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(makerAssetData, this.takerAddress); + const expZRXAssetBalanceOfTaker = await lazyStore.getBalanceAsync(this.zrxAssetData, this.takerAddress); + const expZRXAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync( + this.zrxAssetData, + this.takerAddress, + ); + const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient); + + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + const initialFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); + const expFilledTakerAmount = initialFilledTakerAmount.add(takerAssetFillAmount); + + const expFilledMakerAmount = orderUtils.getPartialAmount( + takerAssetFillAmount, + signedOrder.takerAssetAmount, + signedOrder.makerAssetAmount, + ); + + // - Let's fill the order! + const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { + takerAssetFillAmount, + }); + + const actFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); + expect(actFilledTakerAmount).to.be.bignumber.equal(expFilledTakerAmount, 'filledTakerAmount'); + + expect(txReceipt.logs.length).to.be.equal(1, 'logs length'); + // tslint:disable-next-line:no-unnecessary-type-assertion + const log = txReceipt.logs[0] as LogWithDecodedArgs; + expect(log.args.makerAddress).to.be.equal(makerAddress, 'log.args.makerAddress'); + expect(log.args.takerAddress).to.be.equal(this.takerAddress, 'log.args.this.takerAddress'); + expect(log.args.feeRecipientAddress).to.be.equal(feeRecipient, 'log.args.feeRecipientAddress'); + expect(log.args.makerAssetFilledAmount).to.be.bignumber.equal( + expFilledMakerAmount, + 'log.args.makerAssetFilledAmount', + ); + expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal( + takerAssetFillAmount, + 'log.args.takerAssetFilledAmount', + ); + const expMakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.makerFee, + ); + expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); + const expTakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.takerFee, + ); + expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid'); + expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash'); + expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData'); + expect(log.args.takerAssetData).to.be.equal(takerAssetData, 'log.args.takerAssetData'); + + const actMakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData); + expect(actMakerAssetBalanceOfMaker).to.be.bignumber.equal( + expMakerAssetBalanceOfMaker, + 'makerAssetBalanceOfMaker', + ); + + const actMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + makerAssetData, + ); + expect(actMakerAssetAllowanceOfMaker).to.be.bignumber.equal( + expMakerAssetAllowanceOfMaker, + 'makerAssetAllowanceOfMaker', + ); + + const actTakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData); + expect(actTakerAssetBalanceOfMaker).to.be.bignumber.equal( + expTakerAssetBalanceOfMaker, + 'takerAssetBalanceOfMaker', + ); + + const actZRXAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, this.zrxAssetData); + expect(actZRXAssetBalanceOfMaker).to.be.bignumber.equal(expZRXAssetBalanceOfMaker, 'ZRXAssetBalanceOfMaker'); + + const actZRXAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + this.zrxAssetData, + ); + expect(actZRXAssetAllowanceOfMaker).to.be.bignumber.equal( + expZRXAssetAllowanceOfMaker, + 'ZRXAssetAllowanceOfMaker', + ); + + const actTakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData); + expect(actTakerAssetBalanceOfTaker).to.be.bignumber.equal( + expTakerAssetBalanceOfTaker, + 'TakerAssetBalanceOfTaker', + ); + + const actTakerAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( + this.takerAddress, + takerAssetData, + ); + + expect(actTakerAssetAllowanceOfTaker).to.be.bignumber.equal( + expTakerAssetAllowanceOfTaker, + 'TakerAssetAllowanceOfTaker', + ); + + const actMakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData); + expect(actMakerAssetBalanceOfTaker).to.be.bignumber.equal( + expMakerAssetBalanceOfTaker, + 'MakerAssetBalanceOfTaker', + ); + + const actZRXAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, this.zrxAssetData); + expect(actZRXAssetBalanceOfTaker).to.be.bignumber.equal(expZRXAssetBalanceOfTaker, 'ZRXAssetBalanceOfTaker'); + + const actZRXAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( + this.takerAddress, + this.zrxAssetData, + ); + expect(actZRXAssetAllowanceOfTaker).to.be.bignumber.equal( + expZRXAssetAllowanceOfTaker, + 'ZRXAssetAllowanceOfTaker', + ); + + const actZRXAssetBalanceOfFeeRecipient = await this.assetWrapper.getBalanceAsync( + feeRecipient, + this.zrxAssetData, + ); + expect(actZRXAssetBalanceOfFeeRecipient).to.be.bignumber.equal( + expZRXAssetBalanceOfFeeRecipient, + 'ZRXAssetBalanceOfFeeRecipient', + ); + } +} diff --git a/packages/contracts/src/utils/exchange_wrapper.ts b/packages/contracts/src/utils/exchange_wrapper.ts index 1ecabcf64..e74b91fe2 100644 --- a/packages/contracts/src/utils/exchange_wrapper.ts +++ b/packages/contracts/src/utils/exchange_wrapper.ts @@ -227,6 +227,10 @@ export class ExchangeWrapper { const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex)); return filledAmount; } + public async isCancelledAsync(orderHashHex: string): Promise { + const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex); + return isCancelled; + } public async getOrderInfoAsync(signedOrder: SignedOrder): Promise { const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo; return orderInfo; diff --git a/packages/contracts/src/utils/new_order_factory.ts b/packages/contracts/src/utils/new_order_factory.ts index a4ded4230..715e38d6d 100644 --- a/packages/contracts/src/utils/new_order_factory.ts +++ b/packages/contracts/src/utils/new_order_factory.ts @@ -2,7 +2,7 @@ import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-util import { Order } from '@0xproject/types'; import { BigNumber, errorUtils } from '@0xproject/utils'; -import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token'; +import { DummyERC721TokenContract } from '../generated_contract_wrappers/dummy_e_r_c721_token'; import { constants } from './constants'; import { @@ -11,20 +11,13 @@ import { ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, OrderAmountScenario, + OrderScenario, } from './types'; const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); const ONE_NFT_UNIT = new BigNumber(1); -const TEN_MINUTES_MS = 1000 * 60 * 10; - -/* - * TODO: - * - Write function that given an order, fillAmount, retrieves orderRelevantState and maps it to expected test outcome. - * - Write function that generates order permutations. - * - Write functions for other steps that must be permutated - */ export class NewOrderFactory { private _userAddresses: string[]; @@ -51,16 +44,7 @@ export class NewOrderFactory { this._erc721Balances = erc721Balances; this._exchangeAddress = exchangeAddress; } - public generateOrder( - feeRecipientScenario: FeeRecipientAddressScenario, - makerAssetAmountScenario: OrderAmountScenario, - takerAssetAmountScenario: OrderAmountScenario, - makerFeeScenario: OrderAmountScenario, - takerFeeScenario: OrderAmountScenario, - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario, - makerAssetDataScenario: AssetDataScenario, - takerAssetDataScenario: AssetDataScenario, - ): Order { + public generateOrder(orderScenario: OrderScenario): Order { const makerAddress = this._userAddresses[1]; const takerAddress = this._userAddresses[2]; const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address]; @@ -74,7 +58,7 @@ export class NewOrderFactory { let makerAssetData; let takerAssetData; - switch (feeRecipientScenario) { + switch (orderScenario.feeRecipientScenario) { case FeeRecipientAddressScenario.BurnAddress: feeRecipientAddress = constants.NULL_ADDRESS; break; @@ -82,135 +66,102 @@ export class NewOrderFactory { feeRecipientAddress = this._userAddresses[4]; break; default: - throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', feeRecipientScenario); + throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario); } - const invalidAssetProxyIdHex = '0A'; - switch (makerAssetDataScenario) { + switch (orderScenario.makerAssetDataScenario) { case AssetDataScenario.ZRXFeeToken: - makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress); + makerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); break; case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetData = assetProxyUtils.encodeERC20ProxyData( + makerAssetData = assetProxyUtils.encodeERC20AssetData( this._nonZrxERC20EighteenDecimalTokenAddresses[0], ); break; case AssetDataScenario.ERC20FiveDecimals: - makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC20InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC20ProxyData( - this._nonZrxERC20EighteenDecimalTokenAddresses[0], - ); - makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - case AssetDataScenario.ERC721ValidAssetProxyId: - makerAssetData = assetProxyUtils.encodeERC721ProxyData( - this._erc721Token.address, - erc721MakerAssetIds[0], - ); + makerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]); break; - case AssetDataScenario.ERC721InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC721ProxyData( + case AssetDataScenario.ERC721: + makerAssetData = assetProxyUtils.encodeERC721AssetData( this._erc721Token.address, erc721MakerAssetIds[0], ); - makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; break; - } default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } - switch (takerAssetDataScenario) { + switch (orderScenario.takerAssetDataScenario) { case AssetDataScenario.ZRXFeeToken: - takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress); + takerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); break; case AssetDataScenario.ERC20NonZRXEighteenDecimals: - takerAssetData = assetProxyUtils.encodeERC20ProxyData( + takerAssetData = assetProxyUtils.encodeERC20AssetData( this._nonZrxERC20EighteenDecimalTokenAddresses[1], ); break; case AssetDataScenario.ERC20FiveDecimals: - takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[1]); + takerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]); break; - case AssetDataScenario.ERC20InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC20ProxyData( - this._nonZrxERC20EighteenDecimalTokenAddresses[1], - ); - takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; - break; - } - case AssetDataScenario.ERC721ValidAssetProxyId: - takerAssetData = assetProxyUtils.encodeERC721ProxyData( - this._erc721Token.address, - erc721TakerAssetIds[0], - ); - break; - case AssetDataScenario.ERC721InvalidAssetProxyId: { - const validAssetData = assetProxyUtils.encodeERC721ProxyData( + case AssetDataScenario.ERC721: + takerAssetData = assetProxyUtils.encodeERC721AssetData( this._erc721Token.address, erc721TakerAssetIds[0], ); - takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`; break; - } default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } - switch (makerAssetAmountScenario) { + switch (orderScenario.makerAssetAmountScenario) { case OrderAmountScenario.NonZero: - switch (makerAssetDataScenario) { + switch (orderScenario.makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ERC20InvalidAssetProxyId: makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; break; case AssetDataScenario.ERC20FiveDecimals: makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; break; - case AssetDataScenario.ERC721ValidAssetProxyId: - case AssetDataScenario.ERC721InvalidAssetProxyId: + case AssetDataScenario.ERC721: makerAssetAmount = ONE_NFT_UNIT; break; default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', makerAssetDataScenario); + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } break; case OrderAmountScenario.Zero: makerAssetAmount = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerAssetAmountScenario); + throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.makerAssetAmountScenario); } - switch (takerAssetAmountScenario) { + switch (orderScenario.takerAssetAmountScenario) { case OrderAmountScenario.NonZero: - switch (takerAssetDataScenario) { + switch (orderScenario.takerAssetDataScenario) { case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ERC20InvalidAssetProxyId: + case AssetDataScenario.ZRXFeeToken: takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; break; case AssetDataScenario.ERC20FiveDecimals: takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; break; - case AssetDataScenario.ERC721ValidAssetProxyId: - case AssetDataScenario.ERC721InvalidAssetProxyId: + case AssetDataScenario.ERC721: takerAssetAmount = ONE_NFT_UNIT; break; default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', takerAssetDataScenario); + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } break; case OrderAmountScenario.Zero: takerAssetAmount = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerAssetAmountScenario); + throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.takerAssetAmountScenario); } - switch (makerFeeScenario) { + switch (orderScenario.makerFeeScenario) { case OrderAmountScenario.NonZero: makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; @@ -218,10 +169,10 @@ export class NewOrderFactory { makerFee = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', makerFeeScenario); + throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.makerFeeScenario); } - switch (takerFeeScenario) { + switch (orderScenario.takerFeeScenario) { case OrderAmountScenario.NonZero: takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; @@ -229,18 +180,21 @@ export class NewOrderFactory { takerFee = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', takerFeeScenario); + throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.takerFeeScenario); } - switch (expirationTimeSecondsScenario) { + switch (orderScenario.expirationTimeSecondsScenario) { case ExpirationTimeSecondsScenario.InFuture: - expirationTimeSeconds = new BigNumber(Date.now() + TEN_MINUTES_MS); + expirationTimeSeconds = new BigNumber(2524604400); // Close to infinite break; case ExpirationTimeSecondsScenario.InPast: - expirationTimeSeconds = new BigNumber(Date.now() - TEN_MINUTES_MS); + expirationTimeSeconds = new BigNumber(0); // Jan 1, 1970 break; default: - throw errorUtils.spawnSwitchErr('ExpirationTimeSecondsScenario', expirationTimeSecondsScenario); + throw errorUtils.spawnSwitchErr( + 'ExpirationTimeSecondsScenario', + orderScenario.expirationTimeSecondsScenario, + ); } const order: Order = { diff --git a/packages/contracts/src/utils/order_info_utils.ts b/packages/contracts/src/utils/order_info_utils.ts deleted file mode 100644 index 9df627da3..000000000 --- a/packages/contracts/src/utils/order_info_utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { assetProxyUtils, OrderStateUtils } from '@0xproject/order-utils'; -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; - -import { ExchangeContract } from '../contract_wrappers/generated/exchange'; - -import { constants } from './constants'; -import { ERC20Wrapper } from './erc20_wrapper'; -import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './simple_erc20_balance_and_allowance_fetcher'; -import { SimpleOrderFilledCancelledFetcher } from './simple_filled_cancelled_fetcher'; - -export class OrderInfoUtils { - private _orderStateUtils: OrderStateUtils; - private _erc20Wrapper: ERC20Wrapper; - constructor(exchangeContract: ExchangeContract, erc20Wrapper: ERC20Wrapper, zrxAddress: string) { - this._erc20Wrapper = erc20Wrapper; - const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(exchangeContract, zrxAddress); - const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher(erc20Wrapper); - this._orderStateUtils = new OrderStateUtils( - simpleERC20BalanceAndProxyAllowanceFetcher, - simpleOrderFilledCancelledFetcher, - ); - } - public async getFillableTakerAssetAmountAsync(signedOrder: SignedOrder, takerAddress: string): Promise { - const orderRelevantState = await this._orderStateUtils.getOrderRelevantStateAsync(signedOrder); - console.log('orderRelevantState', orderRelevantState); - if (takerAddress === constants.NULL_ADDRESS) { - return orderRelevantState.remainingFillableTakerAssetAmount; - } - const takerAssetData = assetProxyUtils.decodeERC20ProxyData(signedOrder.takerAssetData); - const takerBalance = await this._erc20Wrapper.getBalanceAsync(takerAddress, takerAssetData.tokenAddress); - const takerAllowance = await this._erc20Wrapper.getProxyAllowanceAsync( - takerAddress, - takerAssetData.tokenAddress, - ); - // TODO: We also need to make sure taker has sufficient ZRX for fees... - const fillableTakerAssetAmount = BigNumber.min([ - takerBalance, - takerAllowance, - orderRelevantState.remainingFillableTakerAssetAmount, - ]); - return fillableTakerAssetAmount; - } -} diff --git a/packages/contracts/src/utils/order_utils.ts b/packages/contracts/src/utils/order_utils.ts index 2a8791e4c..40643fa75 100644 --- a/packages/contracts/src/utils/order_utils.ts +++ b/packages/contracts/src/utils/order_utils.ts @@ -4,6 +4,13 @@ import { BigNumber } from '@0xproject/utils'; import { CancelOrder, MatchOrder } from './types'; export const orderUtils = { + getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + const partialAmount = numerator + .mul(target) + .div(denominator) + .floor(); + return partialAmount; + }, createFill: (signedOrder: SignedOrder, takerAssetFillAmount?: BigNumber) => { const fill = { order: orderUtils.getOrderWithoutExchangeAddress(signedOrder), diff --git a/packages/contracts/src/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/packages/contracts/src/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts new file mode 100644 index 000000000..a295a40c4 --- /dev/null +++ b/packages/contracts/src/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts @@ -0,0 +1,19 @@ +import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; + +import { AssetWrapper } from './asset_wrapper'; + +export class SimpleAssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { + private _assetWrapper: AssetWrapper; + constructor(assetWrapper: AssetWrapper) { + this._assetWrapper = assetWrapper; + } + public async getBalanceAsync(assetData: string, userAddress: string): Promise { + const balance = await this._assetWrapper.getBalanceAsync(userAddress, assetData); + return balance; + } + public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { + const proxyAllowance = await this._assetWrapper.getProxyAllowanceAsync(userAddress, assetData); + return proxyAllowance; + } +} diff --git a/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts b/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts deleted file mode 100644 index 6eed9227a..000000000 --- a/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils'; -import { BigNumber } from '@0xproject/utils'; - -import { ERC20Wrapper } from './erc20_wrapper'; - -// TODO(fabio): Refactor this to also work for ERC721! -export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { - private _erc20TokenWrapper: ERC20Wrapper; - constructor(erc20TokenWrapper: ERC20Wrapper) { - this._erc20TokenWrapper = erc20TokenWrapper; - } - public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise { - const balance = await this._erc20TokenWrapper.getBalanceAsync(userAddress, tokenAddress); - return balance; - } - public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise { - const proxyAllowance = await this._erc20TokenWrapper.getProxyAllowanceAsync(userAddress, tokenAddress); - return proxyAllowance; - } -} diff --git a/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts b/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts deleted file mode 100644 index 0a80637cc..000000000 --- a/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils'; -import { BigNumber } from '@0xproject/utils'; -import { BlockParamLiteral } from 'ethereum-types'; - -import { - CancelContractEventArgs, - ExchangeContract, - FillContractEventArgs, -} from '../contract_wrappers/generated/exchange'; - -export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { - private _exchangeContract: ExchangeContract; - private _zrxAddress: string; - constructor(exchange: ExchangeContract, zrxAddress: string) { - this._exchangeContract = exchange; - this._zrxAddress = zrxAddress; - } - public async getFilledTakerAmountAsync(orderHash: string): Promise { - const filledTakerAmount = new BigNumber(await this._exchangeContract.filled.callAsync(orderHash)); - return filledTakerAmount; - } - public async isOrderCancelledAsync(orderHash: string): Promise { - const methodOpts = { - defaultBlock: BlockParamLiteral.Latest, - }; - const isCancelled = await this._exchangeContract.cancelled.callAsync(orderHash); - return isCancelled; - } - public getZRXTokenAddress(): string { - return this._zrxAddress; - } -} diff --git a/packages/contracts/src/utils/simple_order_filled_cancelled_fetcher.ts b/packages/contracts/src/utils/simple_order_filled_cancelled_fetcher.ts new file mode 100644 index 000000000..24afe36b7 --- /dev/null +++ b/packages/contracts/src/utils/simple_order_filled_cancelled_fetcher.ts @@ -0,0 +1,24 @@ +import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; + +import { ExchangeWrapper } from './exchange_wrapper'; + +export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { + private _exchangeWrapper: ExchangeWrapper; + private _zrxAssetData: string; + constructor(exchange: ExchangeWrapper, zrxAssetData: string) { + this._exchangeWrapper = exchange; + this._zrxAssetData = zrxAssetData; + } + public async getFilledTakerAmountAsync(orderHash: string): Promise { + const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash)); + return filledTakerAmount; + } + public async isOrderCancelledAsync(orderHash: string): Promise { + const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash); + return isCancelled; + } + public getZRXAssetData(): string { + return this._zrxAssetData; + } +} diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index a6e1cd6d0..77e8d867e 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -169,10 +169,19 @@ export enum ExpirationTimeSecondsScenario { } export enum AssetDataScenario { - ERC721ValidAssetProxyId = 'ERC721_VALID_ASSET_PROXY_ID', - ERC721InvalidAssetProxyId = 'ERC721_INVALID_ASSET_PROXY_ID', + ERC721 = 'ERC721', ZRXFeeToken = 'ZRX_FEE_TOKEN', - ERC20InvalidAssetProxyId = 'ERC20_INVALID_ASSET_PROXY_ID', ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', } + +export interface OrderScenario { + feeRecipientScenario: FeeRecipientAddressScenario; + makerAssetAmountScenario: OrderAmountScenario; + takerAssetAmountScenario: OrderAmountScenario; + makerFeeScenario: OrderAmountScenario; + takerFeeScenario: OrderAmountScenario; + expirationTimeSecondsScenario: ExpirationTimeSecondsScenario; + makerAssetDataScenario: AssetDataScenario; + takerAssetDataScenario: AssetDataScenario; +} -- cgit v1.2.3 From 98405a39dbb870c1eb9f562afca4539602917c67 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 14 Jun 2018 10:40:17 +0200 Subject: Add ability to specify takerAssetFillAmount and taker scenarios as part of a FillScenario --- .../src/utils/core_combinatorial_utils.ts | 79 +++++++++++++++------- packages/contracts/src/utils/new_order_factory.ts | 69 +++++++++++++++++-- packages/contracts/src/utils/types.ts | 22 +++++- 3 files changed, 141 insertions(+), 29 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 6fbd8304e..dac4e9edd 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -7,7 +7,7 @@ import { OrderValidationUtils, } from '@0xproject/order-utils'; import { AssetProxyId, Order, SignatureType, SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; +import { BigNumber, errorUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { BlockParamLiteral, LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; @@ -35,6 +35,9 @@ import { FeeRecipientAddressScenario, OrderAmountScenario, OrderScenario, + TakerAssetFillAmountScenario, + TakerScenario, + FillScenario, } from '../utils/types'; chaiSetup.configure(); @@ -142,11 +145,12 @@ export class CoreCombinatorialUtils { public exchangeWrapper: ExchangeWrapper; public assetWrapper: AssetWrapper; public static generateOrderCombinations(): OrderScenario[] { + const takerScenarios = [TakerScenario.Unspecified]; const feeRecipientScenarios = [FeeRecipientAddressScenario.EthUserAddress]; - const makerAssetAmountScenario = [OrderAmountScenario.NonZero]; - const takerAssetAmountScenario = [OrderAmountScenario.NonZero]; - const makerFeeScenario = [OrderAmountScenario.NonZero]; - const takerFeeScenario = [OrderAmountScenario.NonZero]; + const makerAssetAmountScenario = [OrderAmountScenario.Large]; + const takerAssetAmountScenario = [OrderAmountScenario.Large]; + const makerFeeScenario = [OrderAmountScenario.Large]; + const takerFeeScenario = [OrderAmountScenario.Large]; const expirationTimeSecondsScenario = [ExpirationTimeSecondsScenario.InFuture]; const makerAssetDataScenario = [ AssetDataScenario.ERC20FiveDecimals, @@ -161,6 +165,7 @@ export class CoreCombinatorialUtils { AssetDataScenario.ZRXFeeToken, ]; const orderScenarioArrays = CoreCombinatorialUtils._allPossibleCases([ + takerScenarios, feeRecipientScenarios, makerAssetAmountScenario, takerAssetAmountScenario, @@ -173,14 +178,15 @@ export class CoreCombinatorialUtils { const orderScenarios = _.map(orderScenarioArrays, orderScenarioArray => { const orderScenario: OrderScenario = { - feeRecipientScenario: orderScenarioArray[0] as FeeRecipientAddressScenario, - makerAssetAmountScenario: orderScenarioArray[1] as OrderAmountScenario, - takerAssetAmountScenario: orderScenarioArray[2] as OrderAmountScenario, - makerFeeScenario: orderScenarioArray[3] as OrderAmountScenario, - takerFeeScenario: orderScenarioArray[4] as OrderAmountScenario, - expirationTimeSecondsScenario: orderScenarioArray[5] as ExpirationTimeSecondsScenario, - makerAssetDataScenario: orderScenarioArray[6] as AssetDataScenario, - takerAssetDataScenario: orderScenarioArray[7] as AssetDataScenario, + takerScenario: orderScenarioArray[0] as TakerScenario, + feeRecipientScenario: orderScenarioArray[1] as FeeRecipientAddressScenario, + makerAssetAmountScenario: orderScenarioArray[2] as OrderAmountScenario, + takerAssetAmountScenario: orderScenarioArray[3] as OrderAmountScenario, + makerFeeScenario: orderScenarioArray[4] as OrderAmountScenario, + takerFeeScenario: orderScenarioArray[5] as OrderAmountScenario, + expirationTimeSecondsScenario: orderScenarioArray[6] as ExpirationTimeSecondsScenario, + makerAssetDataScenario: orderScenarioArray[7] as AssetDataScenario, + takerAssetDataScenario: orderScenarioArray[8] as AssetDataScenario, }; return orderScenario; }); @@ -225,7 +231,10 @@ export class CoreCombinatorialUtils { this.exchangeWrapper = exchangeWrapper; this.assetWrapper = assetWrapper; } - public async testFillOrderScenarioAsync(order: Order, provider: Provider): Promise { + public async testFillOrderScenarioAsync(provider: Provider, fillScenario: FillScenario): Promise { + // 1. Generate order + const order = this.orderFactory.generateOrder(fillScenario.orderScenario); + // 2. Sign order const orderHashBuff = orderHashUtils.getOrderHashBuff(order); const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign); @@ -235,8 +244,9 @@ export class CoreCombinatorialUtils { }; // 3. Permutate the maker and taker balance/allowance scenarios + // TODO(fabio) - // 4. Figure out fill amount OR error + // 4. Figure out fill amount const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper); const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher( this.exchangeWrapper, @@ -249,14 +259,37 @@ export class CoreCombinatorialUtils { this.takerAddress, ); - // If order is fillable, decide how much to fill - // TODO: Make this configurable - const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); - const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); - const isEitherAssetERC721 = takerAssetProxyId === ERC721_PROXY_ID || makerAssetProxyId === ERC721_PROXY_ID; - const takerAssetFillAmount = isEitherAssetERC721 - ? fillableTakerAssetAmount - : fillableTakerAssetAmount.div(2).floor(); + let takerAssetFillAmount; + const takerAssetFillAmountScenario = fillScenario.takerAssetFillAmountScenario; + switch (takerAssetFillAmountScenario) { + case TakerAssetFillAmountScenario.Zero: + takerAssetFillAmount = new BigNumber(0); + break; + + case TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount: + takerAssetFillAmount = fillableTakerAssetAmount; + break; + + case TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount: + takerAssetFillAmount = fillableTakerAssetAmount.add(1); + break; + + case TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount: + const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); + const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); + const isEitherAssetERC721 = + takerAssetProxyId === ERC721_PROXY_ID || makerAssetProxyId === ERC721_PROXY_ID; + if (isEitherAssetERC721) { + throw new Error( + 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.', + ); + } + takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor(); + break; + + default: + throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario); + } // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts exp? const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); diff --git a/packages/contracts/src/utils/new_order_factory.ts b/packages/contracts/src/utils/new_order_factory.ts index 715e38d6d..7de7be3bd 100644 --- a/packages/contracts/src/utils/new_order_factory.ts +++ b/packages/contracts/src/utils/new_order_factory.ts @@ -12,11 +12,15 @@ import { FeeRecipientAddressScenario, OrderAmountScenario, OrderScenario, + TakerScenario, } from './types'; const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); +const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5000000000000000000); const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); +const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50000000000000000); const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); +const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500000); const ONE_NFT_UNIT = new BigNumber(1); export class NewOrderFactory { @@ -46,7 +50,7 @@ export class NewOrderFactory { } public generateOrder(orderScenario: OrderScenario): Order { const makerAddress = this._userAddresses[1]; - const takerAddress = this._userAddresses[2]; + let takerAddress = this._userAddresses[2]; const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address]; const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address]; let feeRecipientAddress; @@ -114,7 +118,7 @@ export class NewOrderFactory { } switch (orderScenario.makerAssetAmountScenario) { - case OrderAmountScenario.NonZero: + case OrderAmountScenario.Large: switch (orderScenario.makerAssetDataScenario) { case AssetDataScenario.ZRXFeeToken: case AssetDataScenario.ERC20NonZRXEighteenDecimals: @@ -130,6 +134,22 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } break; + case OrderAmountScenario.Small: + switch (orderScenario.makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + makerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); + } + break; case OrderAmountScenario.Zero: makerAssetAmount = new BigNumber(0); break; @@ -138,7 +158,7 @@ export class NewOrderFactory { } switch (orderScenario.takerAssetAmountScenario) { - case OrderAmountScenario.NonZero: + case OrderAmountScenario.Large: switch (orderScenario.takerAssetDataScenario) { case AssetDataScenario.ERC20NonZRXEighteenDecimals: case AssetDataScenario.ZRXFeeToken: @@ -154,6 +174,22 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } break; + case OrderAmountScenario.Small: + switch (orderScenario.takerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ZRXFeeToken: + takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + takerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); + } + break; case OrderAmountScenario.Zero: takerAssetAmount = new BigNumber(0); break; @@ -162,9 +198,12 @@ export class NewOrderFactory { } switch (orderScenario.makerFeeScenario) { - case OrderAmountScenario.NonZero: + case OrderAmountScenario.Large: makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; + case OrderAmountScenario.Small: + makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; + break; case OrderAmountScenario.Zero: makerFee = new BigNumber(0); break; @@ -173,9 +212,12 @@ export class NewOrderFactory { } switch (orderScenario.takerFeeScenario) { - case OrderAmountScenario.NonZero: + case OrderAmountScenario.Large: takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; + case OrderAmountScenario.Small: + takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; + break; case OrderAmountScenario.Zero: takerFee = new BigNumber(0); break; @@ -197,6 +239,23 @@ export class NewOrderFactory { ); } + switch (orderScenario.takerScenario) { + case TakerScenario.CorrectlySpecified: + break; // noop since takerAddress is already specified + + case TakerScenario.IncorrectlySpecified: + const notTaker = this._userAddresses[3]; + takerAddress = notTaker; + break; + + case TakerScenario.Unspecified: + takerAddress = constants.NULL_ADDRESS; + break; + + default: + throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario); + } + const order: Order = { senderAddress: constants.NULL_ADDRESS, makerAddress, diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 77e8d867e..273e8c2d6 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -160,7 +160,14 @@ export enum FeeRecipientAddressScenario { export enum OrderAmountScenario { Zero = 'ZERO', - NonZero = 'NON_ZERO', + Large = 'LARGE', + Small = 'SMALL', +} + +export enum TakerScenario { + CorrectlySpecified = 'CORRECTLY_SPECFIED', + IncorrectlySpecified = 'INCORRECTLY_SPECFIED', + Unspecified = 'UNSPECIFIED', } export enum ExpirationTimeSecondsScenario { @@ -175,7 +182,15 @@ export enum AssetDataScenario { ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', } +export enum TakerAssetFillAmountScenario { + Zero = 'ZERO', + GreaterThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', + LessThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', + ExactlyRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', +} + export interface OrderScenario { + takerScenario: TakerScenario; feeRecipientScenario: FeeRecipientAddressScenario; makerAssetAmountScenario: OrderAmountScenario; takerAssetAmountScenario: OrderAmountScenario; @@ -185,3 +200,8 @@ export interface OrderScenario { makerAssetDataScenario: AssetDataScenario; takerAssetDataScenario: AssetDataScenario; } + +export interface FillScenario { + orderScenario: OrderScenario; + takerAssetFillAmountScenario: TakerAssetFillAmountScenario; +} -- cgit v1.2.3 From 432ff58107704bb4b2fde23f4a99c75f2bca24fa Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 14 Jun 2018 11:16:32 +0200 Subject: Fix calculation of expFilledTakerAmount and expected values in events emitted --- packages/contracts/src/utils/core_combinatorial_utils.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index dac4e9edd..4ce23d450 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -352,11 +352,14 @@ export class CoreCombinatorialUtils { const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const initialFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); - const expFilledTakerAmount = initialFilledTakerAmount.add(takerAssetFillAmount); + const alreadyFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); + const remainingTakerAmountToFill = signedOrder.takerAssetAmount.minus(alreadyFilledTakerAmount); + const expFilledTakerAmount = takerAssetFillAmount.gt(remainingTakerAmountToFill) + ? remainingTakerAmountToFill + : alreadyFilledTakerAmount.add(takerAssetFillAmount); const expFilledMakerAmount = orderUtils.getPartialAmount( - takerAssetFillAmount, + expFilledTakerAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, ); @@ -380,7 +383,7 @@ export class CoreCombinatorialUtils { 'log.args.makerAssetFilledAmount', ); expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal( - takerAssetFillAmount, + expFilledTakerAmount, 'log.args.takerAssetFilledAmount', ); const expMakerFeePaid = orderUtils.getPartialAmount( -- cgit v1.2.3 From 57f37939d5d422d2bac90e7576030ff41b8de7b4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 14 Jun 2018 11:16:51 +0200 Subject: Fix incorrect string values in enum --- packages/contracts/src/utils/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 273e8c2d6..318ea91f9 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -185,8 +185,8 @@ export enum AssetDataScenario { export enum TakerAssetFillAmountScenario { Zero = 'ZERO', GreaterThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', - LessThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', - ExactlyRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', + LessThanRemainingFillableTakerAssetAmount = 'LESS_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', + ExactlyRemainingFillableTakerAssetAmount = 'EXACTLY_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT', } export interface OrderScenario { -- cgit v1.2.3 From 12033abe095e902102f1d56e7a2711a630e6826b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 14 Jun 2018 12:07:57 +0200 Subject: Rename OrderAmountScenario to OrderAssetAmountScenario and convert generateOrderCombinations to generateFillOrderCombinations --- .../src/utils/core_combinatorial_utils.ts | 47 ++++++++++++---------- packages/contracts/src/utils/new_order_factory.ts | 34 ++++++++-------- packages/contracts/src/utils/types.ts | 10 ++--- 3 files changed, 48 insertions(+), 43 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 4ce23d450..776d7b2fe 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -33,11 +33,11 @@ import { AssetDataScenario, ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, - OrderAmountScenario, + FillScenario, + OrderAssetAmountScenario, OrderScenario, TakerAssetFillAmountScenario, TakerScenario, - FillScenario, } from '../utils/types'; chaiSetup.configure(); @@ -144,13 +144,13 @@ export class CoreCombinatorialUtils { public zrxAssetData: string; public exchangeWrapper: ExchangeWrapper; public assetWrapper: AssetWrapper; - public static generateOrderCombinations(): OrderScenario[] { + public static generateFillOrderCombinations(): FillScenario[] { const takerScenarios = [TakerScenario.Unspecified]; const feeRecipientScenarios = [FeeRecipientAddressScenario.EthUserAddress]; - const makerAssetAmountScenario = [OrderAmountScenario.Large]; - const takerAssetAmountScenario = [OrderAmountScenario.Large]; - const makerFeeScenario = [OrderAmountScenario.Large]; - const takerFeeScenario = [OrderAmountScenario.Large]; + const makerAssetAmountScenario = [OrderAssetAmountScenario.Large]; + const takerAssetAmountScenario = [OrderAssetAmountScenario.Large]; + const makerFeeScenario = [OrderAssetAmountScenario.Large]; + const takerFeeScenario = [OrderAssetAmountScenario.Large]; const expirationTimeSecondsScenario = [ExpirationTimeSecondsScenario.InFuture]; const makerAssetDataScenario = [ AssetDataScenario.ERC20FiveDecimals, @@ -164,7 +164,8 @@ export class CoreCombinatorialUtils { AssetDataScenario.ERC721, AssetDataScenario.ZRXFeeToken, ]; - const orderScenarioArrays = CoreCombinatorialUtils._allPossibleCases([ + const takerAssetFillAmountScenario = [TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount]; + const fillScenarioArrays = CoreCombinatorialUtils._allPossibleCases([ takerScenarios, feeRecipientScenarios, makerAssetAmountScenario, @@ -174,24 +175,28 @@ export class CoreCombinatorialUtils { expirationTimeSecondsScenario, makerAssetDataScenario, takerAssetDataScenario, + takerAssetFillAmountScenario, ]); - const orderScenarios = _.map(orderScenarioArrays, orderScenarioArray => { - const orderScenario: OrderScenario = { - takerScenario: orderScenarioArray[0] as TakerScenario, - feeRecipientScenario: orderScenarioArray[1] as FeeRecipientAddressScenario, - makerAssetAmountScenario: orderScenarioArray[2] as OrderAmountScenario, - takerAssetAmountScenario: orderScenarioArray[3] as OrderAmountScenario, - makerFeeScenario: orderScenarioArray[4] as OrderAmountScenario, - takerFeeScenario: orderScenarioArray[5] as OrderAmountScenario, - expirationTimeSecondsScenario: orderScenarioArray[6] as ExpirationTimeSecondsScenario, - makerAssetDataScenario: orderScenarioArray[7] as AssetDataScenario, - takerAssetDataScenario: orderScenarioArray[8] as AssetDataScenario, + const fillScenarios = _.map(fillScenarioArrays, fillScenarioArray => { + const fillScenario: FillScenario = { + orderScenario: { + takerScenario: fillScenarioArray[0] as TakerScenario, + feeRecipientScenario: fillScenarioArray[1] as FeeRecipientAddressScenario, + makerAssetAmountScenario: fillScenarioArray[2] as OrderAssetAmountScenario, + takerAssetAmountScenario: fillScenarioArray[3] as OrderAssetAmountScenario, + makerFeeScenario: fillScenarioArray[4] as OrderAssetAmountScenario, + takerFeeScenario: fillScenarioArray[5] as OrderAssetAmountScenario, + expirationTimeSecondsScenario: fillScenarioArray[6] as ExpirationTimeSecondsScenario, + makerAssetDataScenario: fillScenarioArray[7] as AssetDataScenario, + takerAssetDataScenario: fillScenarioArray[8] as AssetDataScenario, + }, + takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario, }; - return orderScenario; + return fillScenario; }); - return orderScenarios; + return fillScenarios; } private static _allPossibleCases(arrays: string[][]): string[][] { if (arrays.length === 1) { diff --git a/packages/contracts/src/utils/new_order_factory.ts b/packages/contracts/src/utils/new_order_factory.ts index 7de7be3bd..22705d3e7 100644 --- a/packages/contracts/src/utils/new_order_factory.ts +++ b/packages/contracts/src/utils/new_order_factory.ts @@ -10,7 +10,7 @@ import { ERC721TokenIdsByOwner, ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, - OrderAmountScenario, + OrderAssetAmountScenario, OrderScenario, TakerScenario, } from './types'; @@ -118,7 +118,7 @@ export class NewOrderFactory { } switch (orderScenario.makerAssetAmountScenario) { - case OrderAmountScenario.Large: + case OrderAssetAmountScenario.Large: switch (orderScenario.makerAssetDataScenario) { case AssetDataScenario.ZRXFeeToken: case AssetDataScenario.ERC20NonZRXEighteenDecimals: @@ -134,7 +134,7 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } break; - case OrderAmountScenario.Small: + case OrderAssetAmountScenario.Small: switch (orderScenario.makerAssetDataScenario) { case AssetDataScenario.ZRXFeeToken: case AssetDataScenario.ERC20NonZRXEighteenDecimals: @@ -150,15 +150,15 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } break; - case OrderAmountScenario.Zero: + case OrderAssetAmountScenario.Zero: makerAssetAmount = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.makerAssetAmountScenario); + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerAssetAmountScenario); } switch (orderScenario.takerAssetAmountScenario) { - case OrderAmountScenario.Large: + case OrderAssetAmountScenario.Large: switch (orderScenario.takerAssetDataScenario) { case AssetDataScenario.ERC20NonZRXEighteenDecimals: case AssetDataScenario.ZRXFeeToken: @@ -174,7 +174,7 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } break; - case OrderAmountScenario.Small: + case OrderAssetAmountScenario.Small: switch (orderScenario.takerAssetDataScenario) { case AssetDataScenario.ERC20NonZRXEighteenDecimals: case AssetDataScenario.ZRXFeeToken: @@ -190,39 +190,39 @@ export class NewOrderFactory { throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } break; - case OrderAmountScenario.Zero: + case OrderAssetAmountScenario.Zero: takerAssetAmount = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.takerAssetAmountScenario); + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerAssetAmountScenario); } switch (orderScenario.makerFeeScenario) { - case OrderAmountScenario.Large: + case OrderAssetAmountScenario.Large: makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; - case OrderAmountScenario.Small: + case OrderAssetAmountScenario.Small: makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; break; - case OrderAmountScenario.Zero: + case OrderAssetAmountScenario.Zero: makerFee = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.makerFeeScenario); + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerFeeScenario); } switch (orderScenario.takerFeeScenario) { - case OrderAmountScenario.Large: + case OrderAssetAmountScenario.Large: takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; break; - case OrderAmountScenario.Small: + case OrderAssetAmountScenario.Small: takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; break; - case OrderAmountScenario.Zero: + case OrderAssetAmountScenario.Zero: takerFee = new BigNumber(0); break; default: - throw errorUtils.spawnSwitchErr('OrderAmountScenario', orderScenario.takerFeeScenario); + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerFeeScenario); } switch (orderScenario.expirationTimeSecondsScenario) { diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 318ea91f9..f0e2dde02 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -158,7 +158,7 @@ export enum FeeRecipientAddressScenario { EthUserAddress = 'ETH_USER_ADDRESS', } -export enum OrderAmountScenario { +export enum OrderAssetAmountScenario { Zero = 'ZERO', Large = 'LARGE', Small = 'SMALL', @@ -192,10 +192,10 @@ export enum TakerAssetFillAmountScenario { export interface OrderScenario { takerScenario: TakerScenario; feeRecipientScenario: FeeRecipientAddressScenario; - makerAssetAmountScenario: OrderAmountScenario; - takerAssetAmountScenario: OrderAmountScenario; - makerFeeScenario: OrderAmountScenario; - takerFeeScenario: OrderAmountScenario; + makerAssetAmountScenario: OrderAssetAmountScenario; + takerAssetAmountScenario: OrderAssetAmountScenario; + makerFeeScenario: OrderAssetAmountScenario; + takerFeeScenario: OrderAssetAmountScenario; expirationTimeSecondsScenario: ExpirationTimeSecondsScenario; makerAssetDataScenario: AssetDataScenario; takerAssetDataScenario: AssetDataScenario; -- cgit v1.2.3 From eea86757d5cdd63de4b0b06f7dd76fc2c2ddbd36 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 15 Jun 2018 00:00:02 +0200 Subject: - Refactor assetWrapper to contain more of the normalizing logic instead of erc20Wrapper and erc721Wrapper - Add burn method to DummyERC721Token - Add additional methods to assetWrapper to set balance/allowances on ERC20 and ERC721 tokens - Use approve instead of approveAll for ERC721 tokens --- packages/contracts/src/utils/asset_wrapper.ts | 185 +++++++++++++++++++++++-- packages/contracts/src/utils/constants.ts | 2 + packages/contracts/src/utils/erc20_wrapper.ts | 48 ++++--- packages/contracts/src/utils/erc721_wrapper.ts | 127 +++++++++++------ 4 files changed, 295 insertions(+), 67 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index 4c345aa30..462a5086a 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -1,9 +1,13 @@ import { assetProxyUtils } from '@0xproject/order-utils'; -import { BigNumber } from '@0xproject/utils'; +import { BigNumber, errorUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import { AbstractAssetWrapper } from '../abstract/abstract_asset_wrapper'; +import { constants } from './constants'; +import { ERC20Wrapper } from './erc20_wrapper'; +import { ERC721Wrapper } from './erc721_wrapper'; + interface ProxyIdToAssetWrappers { [proxyId: number]: AbstractAssetWrapper; } @@ -17,16 +21,179 @@ export class AssetWrapper { this._proxyIdToAssetWrappers[proxyId] = assetWrapper; }); } - public async getBalanceAsync(owner: string, assetData: string): Promise { + public async getBalanceAsync(userAddress: string, assetData: string): Promise { + const proxyId = assetProxyUtils.decodeAssetDataId(assetData); + switch (proxyId) { + case constants.ERC20_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + const balance = await assetWrapper.getBalanceAsync(userAddress, assetData); + return balance; + } + + case constants.ERC721_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; + const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + const isOwner = await assetWrapper.isOwnerAsync( + userAddress, + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + const balance = isOwner ? new BigNumber(1) : new BigNumber(0); + return balance; + } + + default: + throw errorUtils.spawnSwitchErr('proxyId', proxyId); + } + } + public async setBalanceAsync(userAddress: string, assetData: string, desiredBalance: BigNumber): Promise { + const proxyId = assetProxyUtils.decodeAssetDataId(assetData); + switch (proxyId) { + case constants.ERC20_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + await assetWrapper.setBalanceAsync(userAddress, assetData, desiredBalance); + return; + } + + case constants.ERC721_PROXY_ID: { + if (!desiredBalance.eq(0) && !desiredBalance.eq(1)) { + throw new Error(`Balance for ERC721 token can only be set to 0 or 1. Got: ${desiredBalance}`); + } + const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; + const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + const doesTokenExist = erc721Wrapper.doesTokenExistAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + if (!doesTokenExist && desiredBalance.eq(1)) { + await erc721Wrapper.mintAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress); + return; + } else if (!doesTokenExist && desiredBalance.eq(0)) { + return; // noop + } + const tokenOwner = await erc721Wrapper.ownerOfAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + if (userAddress !== tokenOwner && desiredBalance.eq(1)) { + await erc721Wrapper.transferFromAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + tokenOwner, + userAddress, + ); + } else if ( + (userAddress !== tokenOwner && desiredBalance.eq(0)) || + (tokenOwner === userAddress && desiredBalance.eq(1)) + ) { + return; // noop + } else if (tokenOwner === userAddress && desiredBalance.eq(0)) { + // Burn token + await erc721Wrapper.burnAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress); + return; + } + break; + } + + default: + throw errorUtils.spawnSwitchErr('proxyId', proxyId); + } + } + public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); - const assetWrapper = this._proxyIdToAssetWrappers[proxyId]; - const balance = await assetWrapper.getBalanceAsync(owner, assetData); - return balance; + switch (proxyId) { + case constants.ERC20_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + const allowance = await assetWrapper.getProxyAllowanceAsync(userAddress, assetData); + return allowance; + } + + case constants.ERC721_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; + const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + const isProxyApproved = await assetWrapper.isProxyApprovedAsync( + erc721ProxyData.tokenAddress, + erc721ProxyData.tokenId, + ); + const isProxyApprovedForAllAsync = await assetWrapper.isProxyApprovedForAllAsync( + userAddress, + erc721ProxyData.tokenAddress, + erc721ProxyData.tokenId, + ); + const allowance = isProxyApproved || isProxyApprovedForAllAsync ? new BigNumber(1) : new BigNumber(0); + return allowance; + } + + default: + throw errorUtils.spawnSwitchErr('proxyId', proxyId); + } } - public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { + public async setProxyAllowanceAsync( + userAddress: string, + assetData: string, + desiredAllowance: BigNumber, + ): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); - const assetWrapper = this._proxyIdToAssetWrappers[proxyId]; - const balance = await assetWrapper.getProxyAllowanceAsync(owner, assetData); - return balance; + switch (proxyId) { + case constants.ERC20_PROXY_ID: { + const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + await assetWrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); + return; + } + + case constants.ERC721_PROXY_ID: { + if (!desiredAllowance.eq(0) && !desiredAllowance.eq(1)) { + throw new Error(`Allowance for ERC721 token can only be set to 0 or 1. Got: ${desiredAllowance}`); + } + const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; + const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); + + const doesTokenExist = await erc721Wrapper.doesTokenExistAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + if (!doesTokenExist) { + throw new Error( + `Cannot setProxyAllowance on non-existent token: ${assetProxyData.tokenAddress} ${ + assetProxyData.tokenId + }`, + ); + } + const isProxyApprovedForAll = await erc721Wrapper.isProxyApprovedForAllAsync( + userAddress, + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + // TODO: We should have a way to deal with this. Things get hairier once we are testing + // batch fills + if (isProxyApprovedForAll) { + throw new Error(`We don't currently support the use of "approveAll" functionality for ERC721.`); + } + + const isProxyApproved = await erc721Wrapper.isProxyApprovedAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + if (!isProxyApproved && desiredAllowance.eq(1)) { + await erc721Wrapper.approveProxyAsync(assetProxyData.tokenAddress, assetProxyData.tokenId); + } else if (isProxyApproved && desiredAllowance.eq(0)) { + await erc721Wrapper.approveAsync( + constants.NULL_ADDRESS, + assetProxyData.tokenAddress, + assetProxyData.tokenId, + ); + } else if ( + (!isProxyApproved && desiredAllowance.eq(0)) || + (isProxyApproved && desiredAllowance.eq(1)) + ) { + return; // noop + } + + break; + } + + default: + throw errorUtils.spawnSwitchErr('proxyId', proxyId); + } } } diff --git a/packages/contracts/src/utils/constants.ts b/packages/contracts/src/utils/constants.ts index ec3c8fd36..c8b684c41 100644 --- a/packages/contracts/src/utils/constants.ts +++ b/packages/contracts/src/utils/constants.ts @@ -27,6 +27,8 @@ export const constants = { LIB_BYTES_GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED', ERC20_INSUFFICIENT_BALANCE: 'Insufficient balance to complete transfer.', ERC20_INSUFFICIENT_ALLOWANCE: 'Insufficient allowance to complete transfer.', + ERC20_PROXY_ID: 1, + ERC721_PROXY_ID: 2, TESTRPC_NETWORK_ID: 50, // Note(albrow): In practice V8 and most other engines limit the minimum // interval for setInterval to 10ms. We still set it to 0 here in order to diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index 2d367ae1c..ca2ca492b 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -83,29 +83,30 @@ export class ERC20Wrapper { } } } - public async getBalanceAsync(owner: string, assetData: string): Promise { - const erc20ProxyData = assetProxyUtils.decodeERC20AssetData(assetData); - const tokenAddress = erc20ProxyData.tokenAddress; - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); - if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } - const balance = new BigNumber(await tokenContractIfExists.balanceOf.callAsync(owner)); + public async getBalanceAsync(userAddress: string, assetData: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(assetData); + const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress)); return balance; } - public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { - const erc20ProxyData = assetProxyUtils.decodeERC20AssetData(assetData); - const tokenAddress = erc20ProxyData.tokenAddress; - this._validateProxyContractExistsOrThrow(); - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); - if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } - const allowance = new BigNumber( - await tokenContractIfExists.allowance.callAsync(owner, (this._proxyContract as ERC20ProxyContract).address), - ); + public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(assetData); + await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, { + from: this._contractOwnerAddress, + }); + } + public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(assetData); + const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; + const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress)); return allowance; } + public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(assetData); + const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; + await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, { + from: userAddress, + }); + } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); const balancesByOwner: ERC20BalancesByOwner = {}; @@ -138,6 +139,15 @@ export class ERC20Wrapper { const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); return tokenAddresses; } + private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract { + const erc20ProxyData = assetProxyUtils.decodeERC20AssetData(assetData); + const tokenAddress = erc20ProxyData.tokenAddress; + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); + } + return tokenContractIfExists; + } private _validateDummyTokenContractsExistOrThrow(): void { if (_.isUndefined(this._dummyTokenContracts)) { throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"'); diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index 6a6f10fa7..7da3b6781 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -63,12 +63,7 @@ export class ERC721Wrapper { for (const tokenOwnerAddress of this._tokenOwnerAddresses) { for (let i = 0; i < constants.NUM_ERC721_TOKENS_TO_MINT; i++) { const tokenId = generatePseudoRandomSalt(); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await dummyTokenContract.mint.sendTransactionAsync(tokenOwnerAddress, tokenId, { - from: this._contractOwnerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); + await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) { this._initialTokenIdsByOwner[tokenOwnerAddress] = { [dummyTokenContract.address]: [], @@ -78,45 +73,92 @@ export class ERC721Wrapper { this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; } this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); + + await this.approveProxyAsync(dummyTokenContract.address, tokenId); } - const shouldApprove = true; - await this._web3Wrapper.awaitTransactionSuccessAsync( - await dummyTokenContract.setApprovalForAll.sendTransactionAsync( - (this._proxyContract as ERC721ProxyContract).address, - shouldApprove, - { from: tokenOwnerAddress }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); } } } - public async getBalanceAsync(owner: string, assetData: string): Promise { - const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); - const tokenAddress = erc721ProxyData.tokenAddress; - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); - if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } - const tokenId = erc721ProxyData.tokenId; - const tokenOwner = await tokenContractIfExists.ownerOf.callAsync(tokenId); - const balance = tokenOwner === owner ? new BigNumber(1) : new BigNumber(0); - return balance; - } - public async getProxyAllowanceAsync(owner: string, assetData: string): Promise { - const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); - const tokenAddress = erc721ProxyData.tokenAddress; + public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const doesExist = await tokenContract.exists.callAsync(tokenId); + return doesExist; + } + public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise { + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + await this.approveAsync(proxyAddress, tokenAddress, tokenId); + } + public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.approve.sendTransactionAsync(to, tokenId, { + from: tokenOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async transferFromAsync( + tokenAddress: string, + tokenId: BigNumber, + currentOwner: string, + userAddress: string, + ): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.transferFrom.sendTransactionAsync(currentOwner, userAddress, tokenId, { + from: currentOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.mint.sendTransactionAsync(userAddress, tokenId, { + from: this._contractOwnerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.burn.sendTransactionAsync(owner, tokenId, { + from: this._contractOwnerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const owner = await tokenContract.ownerOf.callAsync(tokenId); + return owner; + } + public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); + const isOwner = tokenOwner === userAddress; + return isOwner; + } + public async isProxyApprovedForAllAsync( + userAddress: string, + tokenAddress: string, + tokenId: BigNumber, + ): Promise { this._validateProxyContractExistsOrThrow(); - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); - if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); const operator = (this._proxyContract as ERC721ProxyContract).address; - const didApproveAll = await tokenContractIfExists.isApprovedForAll.callAsync(owner, operator); - const tokenId = erc721ProxyData.tokenId; - const allowedAddress = await tokenContractIfExists.getApproved.callAsync(tokenId); - const allowance = allowedAddress === operator || didApproveAll ? new BigNumber(1) : new BigNumber(0); - return allowance; + const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); + return didApproveAll; + } + public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise { + this._validateProxyContractExistsOrThrow(); + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const approvedAddress = await tokenContract.getApproved.callAsync(tokenId); + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + const isProxyAnApprovedOperator = approvedAddress === proxyAddress; + return isProxyAnApprovedOperator; } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); @@ -160,6 +202,13 @@ export class ERC721Wrapper { const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); return tokenAddresses; } + private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract { + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); + } + return tokenContractIfExists; + } private _validateDummyTokenContractsExistOrThrow(): void { if (_.isUndefined(this._dummyTokenContracts)) { throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"'); -- cgit v1.2.3 From fb55def54f44413a8b0a7f001fb18d6eac89e422 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 15 Jun 2018 00:03:00 +0200 Subject: Add ability to tweak the relevant balances/allowances for the maker and taker for a fillScenario. Convert more of the core tests to the declarative form. --- .../src/utils/core_combinatorial_utils.ts | 343 ++++++++++++++++++--- packages/contracts/src/utils/types.ts | 15 + 2 files changed, 323 insertions(+), 35 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 776d7b2fe..1735b3191 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -38,13 +38,13 @@ import { OrderScenario, TakerAssetFillAmountScenario, TakerScenario, + TokenAmountScenario, + TraderStateScenario, } from '../utils/types'; chaiSetup.configure(); const expect = chai.expect; -const ERC721_PROXY_ID = 2; - /** * Instantiates a new instance of CoreCombinatorialUtils. Since this method has some * required async setup, a factory method is required. @@ -192,6 +192,18 @@ export class CoreCombinatorialUtils { takerAssetDataScenario: fillScenarioArray[8] as AssetDataScenario, }, takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario, + makerStateScenario: { + traderAssetBalance: TokenAmountScenario.Higher, + traderAssetAllowance: TokenAmountScenario.Higher, + zrxFeeBalance: TokenAmountScenario.Higher, + zrxFeeAllowance: TokenAmountScenario.Higher, + }, + takerStateScenario: { + traderAssetBalance: TokenAmountScenario.Higher, + traderAssetAllowance: TokenAmountScenario.Higher, + zrxFeeBalance: TokenAmountScenario.Higher, + zrxFeeAllowance: TokenAmountScenario.Higher, + }, }; return fillScenario; }); @@ -248,24 +260,305 @@ export class CoreCombinatorialUtils { signature: `0x${signature.toString('hex')}`, }; - // 3. Permutate the maker and taker balance/allowance scenarios - // TODO(fabio) - - // 4. Figure out fill amount const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper); const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher( this.exchangeWrapper, this.zrxAssetData, ); - const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); + // 3. Figure out fill amount + const takerAssetFillAmount = await this._getTakerAssetFillAmountAsync( + signedOrder, + fillScenario.takerAssetFillAmountScenario, + balanceAndProxyAllowanceFetcher, + orderFilledCancelledFetcher, + ); + + // 4. Permutate the maker and taker balance/allowance scenarios + await this._modifyTraderStateAsync( + fillScenario.makerStateScenario, + fillScenario.takerStateScenario, + signedOrder, + takerAssetFillAmount, + balanceAndProxyAllowanceFetcher, + ); + + // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts exp? + const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); + const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); + const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); + + let isFillFailureExpected = false; + try { + await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTransferSimulator, + provider, + signedOrder, + takerAssetFillAmount, + this.takerAddress, + this.zrxAssetData, + ); + } catch (err) { + isFillFailureExpected = true; + } + + await this._fillOrderAndAssertOutcomeAsync( + signedOrder, + takerAssetFillAmount, + lazyStore, + isFillFailureExpected, + provider, + ); + } + private async _modifyTraderStateAsync( + makerStateScenario: TraderStateScenario, + takerStateScenario: TraderStateScenario, + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, + ): Promise { + const makerAssetFillAmount = orderUtils.getPartialAmount( + takerAssetFillAmount, + signedOrder.takerAssetAmount, + signedOrder.makerAssetAmount, + ); + switch (makerStateScenario.traderAssetBalance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + if (makerAssetFillAmount.eq(0)) { + throw new Error(`Cannot set makerAssetBalanceOfMaker TooLow if makerAssetFillAmount is 0`); + } + const tooLowBalance = makerAssetFillAmount.minus(1); + await this.assetWrapper.setBalanceAsync( + signedOrder.makerAddress, + signedOrder.makerAssetData, + tooLowBalance, + ); + break; + + case TokenAmountScenario.Exact: + const exactBalance = makerAssetFillAmount; + await this.assetWrapper.setBalanceAsync( + signedOrder.makerAddress, + signedOrder.makerAssetData, + exactBalance, + ); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'makerStateScenario.traderAssetBalance', + makerStateScenario.traderAssetBalance, + ); + } + + const makerFee = orderUtils.getPartialAmount( + takerAssetFillAmount, + signedOrder.takerAssetAmount, + signedOrder.makerFee, + ); + switch (makerStateScenario.zrxFeeBalance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + if (makerFee.eq(0)) { + throw new Error(`Cannot set zrxAsserBalanceOfMaker TooLow if makerFee is 0`); + } + const tooLowBalance = makerFee.minus(1); + await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, tooLowBalance); + break; + + case TokenAmountScenario.Exact: + const exactBalance = makerFee; + await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, exactBalance); + break; + + default: + throw errorUtils.spawnSwitchErr('makerStateScenario.zrxFeeBalance', makerStateScenario.zrxFeeBalance); + } + + switch (makerStateScenario.traderAssetAllowance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + const tooLowAllowance = makerAssetFillAmount.minus(1); + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + signedOrder.makerAssetData, + tooLowAllowance, + ); + break; + + case TokenAmountScenario.Exact: + const exactAllowance = makerAssetFillAmount; + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + signedOrder.makerAssetData, + exactAllowance, + ); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'makerStateScenario.traderAssetAllowance', + makerStateScenario.traderAssetAllowance, + ); + } + + switch (makerStateScenario.zrxFeeAllowance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + const tooLowAllowance = makerFee.minus(1); + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + this.zrxAssetData, + tooLowAllowance, + ); + break; + + case TokenAmountScenario.Exact: + const exactAllowance = makerFee; + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + this.zrxAssetData, + exactAllowance, + ); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'makerStateScenario.zrxFeeAllowance', + makerStateScenario.zrxFeeAllowance, + ); + } + + switch (takerStateScenario.traderAssetBalance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + if (takerAssetFillAmount.eq(0)) { + throw new Error(`Cannot set takerAssetBalanceOfTaker TooLow if takerAssetFillAmount is 0`); + } + const tooLowBalance = takerAssetFillAmount.minus(1); + await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, tooLowBalance); + break; + + case TokenAmountScenario.Exact: + const exactBalance = takerAssetFillAmount; + await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, exactBalance); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'takerStateScenario.traderAssetBalance', + takerStateScenario.traderAssetBalance, + ); + } + + const takerFee = orderUtils.getPartialAmount( + takerAssetFillAmount, + signedOrder.takerAssetAmount, + signedOrder.takerFee, + ); + switch (takerStateScenario.zrxFeeBalance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + if (takerFee.eq(0)) { + throw new Error(`Cannot set zrxAssetBalanceOfTaker TooLow if takerFee is 0`); + } + const tooLowBalance = takerFee.minus(1); + await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, tooLowBalance); + break; + + case TokenAmountScenario.Exact: + const exactBalance = takerFee; + await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, exactBalance); + break; + + default: + throw errorUtils.spawnSwitchErr('takerStateScenario.zrxFeeBalance', takerStateScenario.zrxFeeBalance); + } + + switch (takerStateScenario.traderAssetAllowance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + const tooLowAllowance = takerAssetFillAmount.minus(1); + await this.assetWrapper.setProxyAllowanceAsync( + this.takerAddress, + signedOrder.takerAssetData, + tooLowAllowance, + ); + break; + + case TokenAmountScenario.Exact: + const exactAllowance = takerAssetFillAmount; + await this.assetWrapper.setProxyAllowanceAsync( + this.takerAddress, + signedOrder.takerAssetData, + exactAllowance, + ); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'takerStateScenario.traderAssetAllowance', + takerStateScenario.traderAssetAllowance, + ); + } + + switch (takerStateScenario.zrxFeeAllowance) { + case TokenAmountScenario.Higher: + break; // Noop since this is already the default + + case TokenAmountScenario.TooLow: + const tooLowAllowance = takerFee.minus(1); + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.takerAddress, + this.zrxAssetData, + tooLowAllowance, + ); + break; + + case TokenAmountScenario.Exact: + const exactAllowance = takerFee; + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.takerAddress, + this.zrxAssetData, + exactAllowance, + ); + break; + + default: + throw errorUtils.spawnSwitchErr( + 'takerStateScenario.zrxFeeAllowance', + takerStateScenario.zrxFeeAllowance, + ); + } + } + private async _getTakerAssetFillAmountAsync( + signedOrder: SignedOrder, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario, + balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, + orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher, + ): Promise { + const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync( signedOrder, this.takerAddress, ); let takerAssetFillAmount; - const takerAssetFillAmountScenario = fillScenario.takerAssetFillAmountScenario; switch (takerAssetFillAmountScenario) { case TakerAssetFillAmountScenario.Zero: takerAssetFillAmount = new BigNumber(0); @@ -283,7 +576,7 @@ export class CoreCombinatorialUtils { const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); const isEitherAssetERC721 = - takerAssetProxyId === ERC721_PROXY_ID || makerAssetProxyId === ERC721_PROXY_ID; + takerAssetProxyId === constants.ERC721_PROXY_ID || makerAssetProxyId === constants.ERC721_PROXY_ID; if (isEitherAssetERC721) { throw new Error( 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.', @@ -296,32 +589,7 @@ export class CoreCombinatorialUtils { throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario); } - // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts exp? - const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); - const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); - const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); - - let isFillFailureExpected = false; - try { - await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTransferSimulator, - provider, - signedOrder, - takerAssetFillAmount, - this.takerAddress, - this.zrxAssetData, - ); - } catch (err) { - isFillFailureExpected = true; - } - - await this._fillOrderAndAssertOutcomeAsync( - signedOrder, - takerAssetFillAmount, - lazyStore, - isFillFailureExpected, - provider, - ); + return takerAssetFillAmount; } private async _fillOrderAndAssertOutcomeAsync( signedOrder: SignedOrder, @@ -369,6 +637,11 @@ export class CoreCombinatorialUtils { signedOrder.makerAssetAmount, ); + const beforeMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + makerAssetData, + ); + // - Let's fill the order! const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount, diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index f0e2dde02..d71c14495 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -201,7 +201,22 @@ export interface OrderScenario { takerAssetDataScenario: AssetDataScenario; } +export enum TokenAmountScenario { + Exact = 'EXACT', + TooLow = 'TOO_LOW', + Higher = 'HIGHER', +} + +export interface TraderStateScenario { + traderAssetBalance: TokenAmountScenario; + traderAssetAllowance: TokenAmountScenario; + zrxFeeBalance: TokenAmountScenario; + zrxFeeAllowance: TokenAmountScenario; +} + export interface FillScenario { orderScenario: OrderScenario; takerAssetFillAmountScenario: TakerAssetFillAmountScenario; + makerStateScenario: TraderStateScenario; + takerStateScenario: TraderStateScenario; } -- cgit v1.2.3 From 1a0b9e46120dd32b3df3bca5076b26ed8a9c932b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 19 Jun 2018 17:25:08 +0200 Subject: Comments and cleanup --- packages/contracts/src/utils/asset_wrapper.ts | 28 ++++++++------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index 462a5086a..2eb54f290 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -12,6 +12,10 @@ interface ProxyIdToAssetWrappers { [proxyId: number]: AbstractAssetWrapper; } +/** + * This class abstracts away the differences between ERC20 and ERC721 tokens so that + * the logic that uses it does not need to care what standard a token belongs to. + */ export class AssetWrapper { private _proxyIdToAssetWrappers: ProxyIdToAssetWrappers; constructor(assetWrappers: AbstractAssetWrapper[]) { @@ -29,7 +33,6 @@ export class AssetWrapper { const balance = await assetWrapper.getBalanceAsync(userAddress, assetData); return balance; } - case constants.ERC721_PROXY_ID: { const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); @@ -41,7 +44,6 @@ export class AssetWrapper { const balance = isOwner ? new BigNumber(1) : new BigNumber(0); return balance; } - default: throw errorUtils.spawnSwitchErr('proxyId', proxyId); } @@ -54,7 +56,6 @@ export class AssetWrapper { await assetWrapper.setBalanceAsync(userAddress, assetData, desiredBalance); return; } - case constants.ERC721_PROXY_ID: { if (!desiredBalance.eq(0) && !desiredBalance.eq(1)) { throw new Error(`Balance for ERC721 token can only be set to 0 or 1. Got: ${desiredBalance}`); @@ -82,11 +83,6 @@ export class AssetWrapper { tokenOwner, userAddress, ); - } else if ( - (userAddress !== tokenOwner && desiredBalance.eq(0)) || - (tokenOwner === userAddress && desiredBalance.eq(1)) - ) { - return; // noop } else if (tokenOwner === userAddress && desiredBalance.eq(0)) { // Burn token await erc721Wrapper.burnAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress); @@ -94,7 +90,6 @@ export class AssetWrapper { } break; } - default: throw errorUtils.spawnSwitchErr('proxyId', proxyId); } @@ -107,7 +102,6 @@ export class AssetWrapper { const allowance = await assetWrapper.getProxyAllowanceAsync(userAddress, assetData); return allowance; } - case constants.ERC721_PROXY_ID: { const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); @@ -123,7 +117,6 @@ export class AssetWrapper { const allowance = isProxyApproved || isProxyApprovedForAllAsync ? new BigNumber(1) : new BigNumber(0); return allowance; } - default: throw errorUtils.spawnSwitchErr('proxyId', proxyId); } @@ -140,7 +133,6 @@ export class AssetWrapper { await assetWrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); return; } - case constants.ERC721_PROXY_ID: { if (!desiredAllowance.eq(0) && !desiredAllowance.eq(1)) { throw new Error(`Allowance for ERC721 token can only be set to 0 or 1. Got: ${desiredAllowance}`); @@ -164,8 +156,9 @@ export class AssetWrapper { assetProxyData.tokenAddress, assetProxyData.tokenId, ); - // TODO: We should have a way to deal with this. Things get hairier once we are testing - // batch fills + // HACK: We do not currently support ApprovedForAll when setting proxy allowance + // This was intentional since unsetting ApprovedForAll, will unset approval for unrelated + // tokens other then the one specified in the call to this method. if (isProxyApprovedForAll) { throw new Error(`We don't currently support the use of "approveAll" functionality for ERC721.`); } @@ -177,21 +170,16 @@ export class AssetWrapper { if (!isProxyApproved && desiredAllowance.eq(1)) { await erc721Wrapper.approveProxyAsync(assetProxyData.tokenAddress, assetProxyData.tokenId); } else if (isProxyApproved && desiredAllowance.eq(0)) { + // Remove approval await erc721Wrapper.approveAsync( constants.NULL_ADDRESS, assetProxyData.tokenAddress, assetProxyData.tokenId, ); - } else if ( - (!isProxyApproved && desiredAllowance.eq(0)) || - (isProxyApproved && desiredAllowance.eq(1)) - ) { - return; // noop } break; } - default: throw errorUtils.spawnSwitchErr('proxyId', proxyId); } -- cgit v1.2.3 From 70de264d4dd96efce2719c209c4b866c93668877 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 19 Jun 2018 17:31:26 +0200 Subject: Cleanup coreCombinatorialUtils --- .../src/utils/core_combinatorial_utils.ts | 446 +++++++++++---------- 1 file changed, 226 insertions(+), 220 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 1735b3191..d6142c5fb 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -11,7 +11,6 @@ import { BigNumber, errorUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { BlockParamLiteral, LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; -// import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; import 'make-promises-safe'; @@ -165,7 +164,7 @@ export class CoreCombinatorialUtils { AssetDataScenario.ZRXFeeToken, ]; const takerAssetFillAmountScenario = [TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount]; - const fillScenarioArrays = CoreCombinatorialUtils._allPossibleCases([ + const fillScenarioArrays = CoreCombinatorialUtils._getAllCombinations([ takerScenarios, feeRecipientScenarios, makerAssetAmountScenario, @@ -210,19 +209,25 @@ export class CoreCombinatorialUtils { return fillScenarios; } - private static _allPossibleCases(arrays: string[][]): string[][] { + /** + * Recursive implementation of generating all combinations of the supplied + * string-containing arrays. + */ + private static _getAllCombinations(arrays: string[][]): string[][] { + // Base case if (arrays.length === 1) { - const remainingVals = _.map(arrays[0], val => { + const remainingValues = _.map(arrays[0], val => { return [val]; }); - return remainingVals; + return remainingValues; } else { const result = []; - const allCasesOfRest = CoreCombinatorialUtils._allPossibleCases(arrays.slice(1)); // recur with the rest of array + const restOfArrays = arrays.slice(1); + const allCombinationsOfRemaining = CoreCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array // tslint:disable:prefer-for-of - for (let i = 0; i < allCasesOfRest.length; i++) { + for (let i = 0; i < allCombinationsOfRemaining.length; i++) { for (let j = 0; j < arrays[0].length; j++) { - result.push([arrays[0][j], ...allCasesOfRest[i]]); + result.push([arrays[0][j], ...allCombinationsOfRemaining[i]]); } } // tslint:enable:prefer-for-of @@ -283,7 +288,7 @@ export class CoreCombinatorialUtils { balanceAndProxyAllowanceFetcher, ); - // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts exp? + // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected? const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); @@ -302,6 +307,7 @@ export class CoreCombinatorialUtils { isFillFailureExpected = true; } + // 6. Fill the order await this._fillOrderAndAssertOutcomeAsync( signedOrder, takerAssetFillAmount, @@ -310,6 +316,216 @@ export class CoreCombinatorialUtils { provider, ); } + private async _fillOrderAndAssertOutcomeAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + lazyStore: BalanceAndProxyAllowanceLazyStore, + isFillFailureExpected: boolean, + provider: Provider, + ): Promise { + if (isFillFailureExpected) { + return expectRevertOrAlwaysFailingTransactionAsync( + this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), + ); + } + + const makerAddress = signedOrder.makerAddress; + const makerAssetData = signedOrder.makerAssetData; + const takerAssetData = signedOrder.takerAssetData; + const feeRecipient = signedOrder.feeRecipientAddress; + + const expMakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(makerAssetData, makerAddress); + const expMakerAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress); + const expTakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(takerAssetData, makerAddress); + const expZRXAssetBalanceOfMaker = await lazyStore.getBalanceAsync(this.zrxAssetData, makerAddress); + const expZRXAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(this.zrxAssetData, makerAddress); + const expTakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(takerAssetData, this.takerAddress); + const expTakerAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress); + const expMakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(makerAssetData, this.takerAddress); + const expZRXAssetBalanceOfTaker = await lazyStore.getBalanceAsync(this.zrxAssetData, this.takerAddress); + const expZRXAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync( + this.zrxAssetData, + this.takerAddress, + ); + const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient); + + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + const alreadyFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); + const remainingTakerAmountToFill = signedOrder.takerAssetAmount.minus(alreadyFilledTakerAmount); + const expFilledTakerAmount = takerAssetFillAmount.gt(remainingTakerAmountToFill) + ? remainingTakerAmountToFill + : alreadyFilledTakerAmount.add(takerAssetFillAmount); + + const expFilledMakerAmount = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.makerAssetAmount, + ); + + const beforeMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + makerAssetData, + ); + + // - Let's fill the order! + const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { + takerAssetFillAmount, + }); + + const actFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); + expect(actFilledTakerAmount).to.be.bignumber.equal(expFilledTakerAmount, 'filledTakerAmount'); + + expect(txReceipt.logs.length).to.be.equal(1, 'logs length'); + // tslint:disable-next-line:no-unnecessary-type-assertion + const log = txReceipt.logs[0] as LogWithDecodedArgs; + expect(log.args.makerAddress).to.be.equal(makerAddress, 'log.args.makerAddress'); + expect(log.args.takerAddress).to.be.equal(this.takerAddress, 'log.args.this.takerAddress'); + expect(log.args.feeRecipientAddress).to.be.equal(feeRecipient, 'log.args.feeRecipientAddress'); + expect(log.args.makerAssetFilledAmount).to.be.bignumber.equal( + expFilledMakerAmount, + 'log.args.makerAssetFilledAmount', + ); + expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal( + expFilledTakerAmount, + 'log.args.takerAssetFilledAmount', + ); + const expMakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.makerFee, + ); + expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); + const expTakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.takerFee, + ); + expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid'); + expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash'); + expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData'); + expect(log.args.takerAssetData).to.be.equal(takerAssetData, 'log.args.takerAssetData'); + + const actMakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData); + expect(actMakerAssetBalanceOfMaker).to.be.bignumber.equal( + expMakerAssetBalanceOfMaker, + 'makerAssetBalanceOfMaker', + ); + + const actMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + makerAssetData, + ); + expect(actMakerAssetAllowanceOfMaker).to.be.bignumber.equal( + expMakerAssetAllowanceOfMaker, + 'makerAssetAllowanceOfMaker', + ); + + const actTakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData); + expect(actTakerAssetBalanceOfMaker).to.be.bignumber.equal( + expTakerAssetBalanceOfMaker, + 'takerAssetBalanceOfMaker', + ); + + const actZRXAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, this.zrxAssetData); + expect(actZRXAssetBalanceOfMaker).to.be.bignumber.equal(expZRXAssetBalanceOfMaker, 'ZRXAssetBalanceOfMaker'); + + const actZRXAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( + makerAddress, + this.zrxAssetData, + ); + expect(actZRXAssetAllowanceOfMaker).to.be.bignumber.equal( + expZRXAssetAllowanceOfMaker, + 'ZRXAssetAllowanceOfMaker', + ); + + const actTakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData); + expect(actTakerAssetBalanceOfTaker).to.be.bignumber.equal( + expTakerAssetBalanceOfTaker, + 'TakerAssetBalanceOfTaker', + ); + + const actTakerAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( + this.takerAddress, + takerAssetData, + ); + + expect(actTakerAssetAllowanceOfTaker).to.be.bignumber.equal( + expTakerAssetAllowanceOfTaker, + 'TakerAssetAllowanceOfTaker', + ); + + const actMakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData); + expect(actMakerAssetBalanceOfTaker).to.be.bignumber.equal( + expMakerAssetBalanceOfTaker, + 'MakerAssetBalanceOfTaker', + ); + + const actZRXAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, this.zrxAssetData); + expect(actZRXAssetBalanceOfTaker).to.be.bignumber.equal(expZRXAssetBalanceOfTaker, 'ZRXAssetBalanceOfTaker'); + + const actZRXAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( + this.takerAddress, + this.zrxAssetData, + ); + expect(actZRXAssetAllowanceOfTaker).to.be.bignumber.equal( + expZRXAssetAllowanceOfTaker, + 'ZRXAssetAllowanceOfTaker', + ); + + const actZRXAssetBalanceOfFeeRecipient = await this.assetWrapper.getBalanceAsync( + feeRecipient, + this.zrxAssetData, + ); + expect(actZRXAssetBalanceOfFeeRecipient).to.be.bignumber.equal( + expZRXAssetBalanceOfFeeRecipient, + 'ZRXAssetBalanceOfFeeRecipient', + ); + } + private async _getTakerAssetFillAmountAsync( + signedOrder: SignedOrder, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario, + balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, + orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher, + ): Promise { + const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); + const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync( + signedOrder, + this.takerAddress, + ); + + let takerAssetFillAmount; + switch (takerAssetFillAmountScenario) { + case TakerAssetFillAmountScenario.Zero: + takerAssetFillAmount = new BigNumber(0); + break; + + case TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount: + takerAssetFillAmount = fillableTakerAssetAmount; + break; + + case TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount: + takerAssetFillAmount = fillableTakerAssetAmount.add(1); + break; + + case TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount: + const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); + const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); + const isEitherAssetERC721 = + takerAssetProxyId === constants.ERC721_PROXY_ID || makerAssetProxyId === constants.ERC721_PROXY_ID; + if (isEitherAssetERC721) { + throw new Error( + 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.', + ); + } + takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor(); + break; + + default: + throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario); + } + + return takerAssetFillAmount; + } private async _modifyTraderStateAsync( makerStateScenario: TraderStateScenario, takerStateScenario: TraderStateScenario, @@ -546,214 +762,4 @@ export class CoreCombinatorialUtils { ); } } - private async _getTakerAssetFillAmountAsync( - signedOrder: SignedOrder, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario, - balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, - orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher, - ): Promise { - const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); - const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync( - signedOrder, - this.takerAddress, - ); - - let takerAssetFillAmount; - switch (takerAssetFillAmountScenario) { - case TakerAssetFillAmountScenario.Zero: - takerAssetFillAmount = new BigNumber(0); - break; - - case TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount: - takerAssetFillAmount = fillableTakerAssetAmount; - break; - - case TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount: - takerAssetFillAmount = fillableTakerAssetAmount.add(1); - break; - - case TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount: - const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); - const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); - const isEitherAssetERC721 = - takerAssetProxyId === constants.ERC721_PROXY_ID || makerAssetProxyId === constants.ERC721_PROXY_ID; - if (isEitherAssetERC721) { - throw new Error( - 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.', - ); - } - takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor(); - break; - - default: - throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario); - } - - return takerAssetFillAmount; - } - private async _fillOrderAndAssertOutcomeAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - lazyStore: BalanceAndProxyAllowanceLazyStore, - isFillFailureExpected: boolean, - provider: Provider, - ): Promise { - if (isFillFailureExpected) { - return expectRevertOrAlwaysFailingTransactionAsync( - this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), - ); - } - - const makerAddress = signedOrder.makerAddress; - const makerAssetData = signedOrder.makerAssetData; - const takerAssetData = signedOrder.takerAssetData; - const feeRecipient = signedOrder.feeRecipientAddress; - - const expMakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(makerAssetData, makerAddress); - const expMakerAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress); - const expTakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(takerAssetData, makerAddress); - const expZRXAssetBalanceOfMaker = await lazyStore.getBalanceAsync(this.zrxAssetData, makerAddress); - const expZRXAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(this.zrxAssetData, makerAddress); - const expTakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(takerAssetData, this.takerAddress); - const expTakerAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress); - const expMakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(makerAssetData, this.takerAddress); - const expZRXAssetBalanceOfTaker = await lazyStore.getBalanceAsync(this.zrxAssetData, this.takerAddress); - const expZRXAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync( - this.zrxAssetData, - this.takerAddress, - ); - const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient); - - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const alreadyFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); - const remainingTakerAmountToFill = signedOrder.takerAssetAmount.minus(alreadyFilledTakerAmount); - const expFilledTakerAmount = takerAssetFillAmount.gt(remainingTakerAmountToFill) - ? remainingTakerAmountToFill - : alreadyFilledTakerAmount.add(takerAssetFillAmount); - - const expFilledMakerAmount = orderUtils.getPartialAmount( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - - const beforeMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( - makerAddress, - makerAssetData, - ); - - // - Let's fill the order! - const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { - takerAssetFillAmount, - }); - - const actFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash); - expect(actFilledTakerAmount).to.be.bignumber.equal(expFilledTakerAmount, 'filledTakerAmount'); - - expect(txReceipt.logs.length).to.be.equal(1, 'logs length'); - // tslint:disable-next-line:no-unnecessary-type-assertion - const log = txReceipt.logs[0] as LogWithDecodedArgs; - expect(log.args.makerAddress).to.be.equal(makerAddress, 'log.args.makerAddress'); - expect(log.args.takerAddress).to.be.equal(this.takerAddress, 'log.args.this.takerAddress'); - expect(log.args.feeRecipientAddress).to.be.equal(feeRecipient, 'log.args.feeRecipientAddress'); - expect(log.args.makerAssetFilledAmount).to.be.bignumber.equal( - expFilledMakerAmount, - 'log.args.makerAssetFilledAmount', - ); - expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal( - expFilledTakerAmount, - 'log.args.takerAssetFilledAmount', - ); - const expMakerFeePaid = orderUtils.getPartialAmount( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); - expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); - const expTakerFeePaid = orderUtils.getPartialAmount( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); - expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid'); - expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash'); - expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData'); - expect(log.args.takerAssetData).to.be.equal(takerAssetData, 'log.args.takerAssetData'); - - const actMakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData); - expect(actMakerAssetBalanceOfMaker).to.be.bignumber.equal( - expMakerAssetBalanceOfMaker, - 'makerAssetBalanceOfMaker', - ); - - const actMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( - makerAddress, - makerAssetData, - ); - expect(actMakerAssetAllowanceOfMaker).to.be.bignumber.equal( - expMakerAssetAllowanceOfMaker, - 'makerAssetAllowanceOfMaker', - ); - - const actTakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData); - expect(actTakerAssetBalanceOfMaker).to.be.bignumber.equal( - expTakerAssetBalanceOfMaker, - 'takerAssetBalanceOfMaker', - ); - - const actZRXAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, this.zrxAssetData); - expect(actZRXAssetBalanceOfMaker).to.be.bignumber.equal(expZRXAssetBalanceOfMaker, 'ZRXAssetBalanceOfMaker'); - - const actZRXAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( - makerAddress, - this.zrxAssetData, - ); - expect(actZRXAssetAllowanceOfMaker).to.be.bignumber.equal( - expZRXAssetAllowanceOfMaker, - 'ZRXAssetAllowanceOfMaker', - ); - - const actTakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData); - expect(actTakerAssetBalanceOfTaker).to.be.bignumber.equal( - expTakerAssetBalanceOfTaker, - 'TakerAssetBalanceOfTaker', - ); - - const actTakerAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( - this.takerAddress, - takerAssetData, - ); - - expect(actTakerAssetAllowanceOfTaker).to.be.bignumber.equal( - expTakerAssetAllowanceOfTaker, - 'TakerAssetAllowanceOfTaker', - ); - - const actMakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData); - expect(actMakerAssetBalanceOfTaker).to.be.bignumber.equal( - expMakerAssetBalanceOfTaker, - 'MakerAssetBalanceOfTaker', - ); - - const actZRXAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, this.zrxAssetData); - expect(actZRXAssetBalanceOfTaker).to.be.bignumber.equal(expZRXAssetBalanceOfTaker, 'ZRXAssetBalanceOfTaker'); - - const actZRXAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync( - this.takerAddress, - this.zrxAssetData, - ); - expect(actZRXAssetAllowanceOfTaker).to.be.bignumber.equal( - expZRXAssetAllowanceOfTaker, - 'ZRXAssetAllowanceOfTaker', - ); - - const actZRXAssetBalanceOfFeeRecipient = await this.assetWrapper.getBalanceAsync( - feeRecipient, - this.zrxAssetData, - ); - expect(actZRXAssetBalanceOfFeeRecipient).to.be.bignumber.equal( - expZRXAssetBalanceOfFeeRecipient, - 'ZRXAssetBalanceOfFeeRecipient', - ); - } -} +} // tslint:disable:max-file-line-count -- cgit v1.2.3 From 9acf4458c026ca9e2748ca4291573ac95c66fe26 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 19 Jun 2018 17:38:15 +0200 Subject: Remove hack in ERC20Wrapper --- packages/contracts/src/utils/erc20_wrapper.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index ca2ca492b..6dd717f4a 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -27,11 +27,11 @@ export class ERC20Wrapper { this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; } - public async deployDummyTokensAsync(num?: number, decimals?: BigNumber): Promise { - // TODO(fabio): Remove and refactor all tests - const finalNum = _.isUndefined(num) ? constants.NUM_DUMMY_ERC20_TO_DEPLOY : num; - const finalDecimals = _.isUndefined(decimals) ? constants.DUMMY_TOKEN_DECIMALS : decimals; - for (let i = 0; i < finalNum; i++) { + public async deployDummyTokensAsync( + numberToDeploy: number, + decimals: BigNumber, + ): Promise { + for (let i = 0; i < numberToDeploy; i++) { this._dummyTokenContracts.push( await DummyERC20TokenContract.deployFrom0xArtifactAsync( artifacts.DummyERC20Token, @@ -39,7 +39,7 @@ export class ERC20Wrapper { txDefaults, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, - finalDecimals, + decimals, constants.DUMMY_TOKEN_TOTAL_SUPPLY, ), ); -- cgit v1.2.3 From c0e008c601d4c34da6faafce62abfd8e0ff821c5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 19 Jun 2018 17:41:10 +0200 Subject: Rename NewOrderFactory to OrderFactoryFromScenario for clarity --- .../src/utils/core_combinatorial_utils.ts | 8 +- packages/contracts/src/utils/new_order_factory.ts | 277 --------------------- .../src/utils/order_factory_from_scenario.ts | 277 +++++++++++++++++++++ 3 files changed, 281 insertions(+), 281 deletions(-) delete mode 100644 packages/contracts/src/utils/new_order_factory.ts create mode 100644 packages/contracts/src/utils/order_factory_from_scenario.ts (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index d6142c5fb..cdb8e579d 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -23,7 +23,7 @@ import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; -import { NewOrderFactory } from '../utils/new_order_factory'; +import { OrderFactoryFromScenario } from '../utils/order_factory_from_scenario'; import { orderUtils } from '../utils/order_utils'; import { signingUtils } from '../utils/signing_utils'; import { SimpleAssetBalanceAndProxyAllowanceFetcher } from '../utils/simple_asset_balance_and_proxy_allowance_fetcher'; @@ -111,7 +111,7 @@ export async function coreCombinatorialUtilsFactoryAsync( constants.AWAIT_TRANSACTION_MINED_MS, ); - const orderFactory = new NewOrderFactory( + const orderFactory = new OrderFactoryFromScenario( userAddresses, zrxToken.address, [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address], @@ -135,7 +135,7 @@ export async function coreCombinatorialUtilsFactoryAsync( } export class CoreCombinatorialUtils { - public orderFactory: NewOrderFactory; + public orderFactory: OrderFactoryFromScenario; public ownerAddress: string; public makerAddress: string; public makerPrivateKey: Buffer; @@ -235,7 +235,7 @@ export class CoreCombinatorialUtils { } } constructor( - orderFactory: NewOrderFactory, + orderFactory: OrderFactoryFromScenario, ownerAddress: string, makerAddress: string, makerPrivateKey: Buffer, diff --git a/packages/contracts/src/utils/new_order_factory.ts b/packages/contracts/src/utils/new_order_factory.ts deleted file mode 100644 index 22705d3e7..000000000 --- a/packages/contracts/src/utils/new_order_factory.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; -import { Order } from '@0xproject/types'; -import { BigNumber, errorUtils } from '@0xproject/utils'; - -import { DummyERC721TokenContract } from '../generated_contract_wrappers/dummy_e_r_c721_token'; - -import { constants } from './constants'; -import { - AssetDataScenario, - ERC721TokenIdsByOwner, - ExpirationTimeSecondsScenario, - FeeRecipientAddressScenario, - OrderAssetAmountScenario, - OrderScenario, - TakerScenario, -} from './types'; - -const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); -const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5000000000000000000); -const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); -const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50000000000000000); -const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); -const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500000); -const ONE_NFT_UNIT = new BigNumber(1); - -export class NewOrderFactory { - private _userAddresses: string[]; - private _zrxAddress: string; - private _nonZrxERC20EighteenDecimalTokenAddresses: string[]; - private _erc20FiveDecimalTokenAddresses: string[]; - private _erc721Token: DummyERC721TokenContract; - private _erc721Balances: ERC721TokenIdsByOwner; - private _exchangeAddress: string; - constructor( - userAddresses: string[], - zrxAddress: string, - nonZrxERC20EighteenDecimalTokenAddresses: string[], - erc20FiveDecimalTokenAddresses: string[], - erc721Token: DummyERC721TokenContract, - erc721Balances: ERC721TokenIdsByOwner, - exchangeAddress: string, - ) { - this._userAddresses = userAddresses; - this._zrxAddress = zrxAddress; - this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses; - this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses; - this._erc721Token = erc721Token; - this._erc721Balances = erc721Balances; - this._exchangeAddress = exchangeAddress; - } - public generateOrder(orderScenario: OrderScenario): Order { - const makerAddress = this._userAddresses[1]; - let takerAddress = this._userAddresses[2]; - const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address]; - const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address]; - let feeRecipientAddress; - let makerAssetAmount; - let takerAssetAmount; - let makerFee; - let takerFee; - let expirationTimeSeconds; - let makerAssetData; - let takerAssetData; - - switch (orderScenario.feeRecipientScenario) { - case FeeRecipientAddressScenario.BurnAddress: - feeRecipientAddress = constants.NULL_ADDRESS; - break; - case FeeRecipientAddressScenario.EthUserAddress: - feeRecipientAddress = this._userAddresses[4]; - break; - default: - throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario); - } - - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - makerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetData = assetProxyUtils.encodeERC20AssetData( - this._nonZrxERC20EighteenDecimalTokenAddresses[0], - ); - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC721: - makerAssetData = assetProxyUtils.encodeERC721AssetData( - this._erc721Token.address, - erc721MakerAssetIds[0], - ); - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - takerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - takerAssetData = assetProxyUtils.encodeERC20AssetData( - this._nonZrxERC20EighteenDecimalTokenAddresses[1], - ); - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC721: - takerAssetData = assetProxyUtils.encodeERC721AssetData( - this._erc721Token.address, - erc721TakerAssetIds[0], - ); - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); - } - - switch (orderScenario.makerAssetAmountScenario) { - case OrderAssetAmountScenario.Large: - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - makerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Small: - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - makerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Zero: - makerAssetAmount = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerAssetAmountScenario); - } - - switch (orderScenario.takerAssetAmountScenario) { - case OrderAssetAmountScenario.Large: - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ZRXFeeToken: - takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - takerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Small: - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - case AssetDataScenario.ZRXFeeToken: - takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - takerAssetAmount = ONE_NFT_UNIT; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Zero: - takerAssetAmount = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerAssetAmountScenario); - } - - switch (orderScenario.makerFeeScenario) { - case OrderAssetAmountScenario.Large: - makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAssetAmountScenario.Small: - makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAssetAmountScenario.Zero: - makerFee = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerFeeScenario); - } - - switch (orderScenario.takerFeeScenario) { - case OrderAssetAmountScenario.Large: - takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAssetAmountScenario.Small: - takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case OrderAssetAmountScenario.Zero: - takerFee = new BigNumber(0); - break; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerFeeScenario); - } - - switch (orderScenario.expirationTimeSecondsScenario) { - case ExpirationTimeSecondsScenario.InFuture: - expirationTimeSeconds = new BigNumber(2524604400); // Close to infinite - break; - case ExpirationTimeSecondsScenario.InPast: - expirationTimeSeconds = new BigNumber(0); // Jan 1, 1970 - break; - default: - throw errorUtils.spawnSwitchErr( - 'ExpirationTimeSecondsScenario', - orderScenario.expirationTimeSecondsScenario, - ); - } - - switch (orderScenario.takerScenario) { - case TakerScenario.CorrectlySpecified: - break; // noop since takerAddress is already specified - - case TakerScenario.IncorrectlySpecified: - const notTaker = this._userAddresses[3]; - takerAddress = notTaker; - break; - - case TakerScenario.Unspecified: - takerAddress = constants.NULL_ADDRESS; - break; - - default: - throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario); - } - - const order: Order = { - senderAddress: constants.NULL_ADDRESS, - makerAddress, - takerAddress, - makerFee, - takerFee, - makerAssetAmount, - takerAssetAmount, - makerAssetData, - takerAssetData, - salt: generatePseudoRandomSalt(), - exchangeAddress: this._exchangeAddress, - feeRecipientAddress, - expirationTimeSeconds, - }; - - return order; - } -} diff --git a/packages/contracts/src/utils/order_factory_from_scenario.ts b/packages/contracts/src/utils/order_factory_from_scenario.ts new file mode 100644 index 000000000..74c2d4fa2 --- /dev/null +++ b/packages/contracts/src/utils/order_factory_from_scenario.ts @@ -0,0 +1,277 @@ +import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { Order } from '@0xproject/types'; +import { BigNumber, errorUtils } from '@0xproject/utils'; + +import { DummyERC721TokenContract } from '../generated_contract_wrappers/dummy_e_r_c721_token'; + +import { constants } from './constants'; +import { + AssetDataScenario, + ERC721TokenIdsByOwner, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + OrderAssetAmountScenario, + OrderScenario, + TakerScenario, +} from './types'; + +const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); +const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5000000000000000000); +const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); +const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50000000000000000); +const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); +const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500000); +const ONE_NFT_UNIT = new BigNumber(1); + +export class OrderFactoryFromScenario { + private _userAddresses: string[]; + private _zrxAddress: string; + private _nonZrxERC20EighteenDecimalTokenAddresses: string[]; + private _erc20FiveDecimalTokenAddresses: string[]; + private _erc721Token: DummyERC721TokenContract; + private _erc721Balances: ERC721TokenIdsByOwner; + private _exchangeAddress: string; + constructor( + userAddresses: string[], + zrxAddress: string, + nonZrxERC20EighteenDecimalTokenAddresses: string[], + erc20FiveDecimalTokenAddresses: string[], + erc721Token: DummyERC721TokenContract, + erc721Balances: ERC721TokenIdsByOwner, + exchangeAddress: string, + ) { + this._userAddresses = userAddresses; + this._zrxAddress = zrxAddress; + this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses; + this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses; + this._erc721Token = erc721Token; + this._erc721Balances = erc721Balances; + this._exchangeAddress = exchangeAddress; + } + public generateOrder(orderScenario: OrderScenario): Order { + const makerAddress = this._userAddresses[1]; + let takerAddress = this._userAddresses[2]; + const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address]; + const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address]; + let feeRecipientAddress; + let makerAssetAmount; + let takerAssetAmount; + let makerFee; + let takerFee; + let expirationTimeSeconds; + let makerAssetData; + let takerAssetData; + + switch (orderScenario.feeRecipientScenario) { + case FeeRecipientAddressScenario.BurnAddress: + feeRecipientAddress = constants.NULL_ADDRESS; + break; + case FeeRecipientAddressScenario.EthUserAddress: + feeRecipientAddress = this._userAddresses[4]; + break; + default: + throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario); + } + + switch (orderScenario.makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + makerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetData = assetProxyUtils.encodeERC20AssetData( + this._nonZrxERC20EighteenDecimalTokenAddresses[0], + ); + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]); + break; + case AssetDataScenario.ERC721: + makerAssetData = assetProxyUtils.encodeERC721AssetData( + this._erc721Token.address, + erc721MakerAssetIds[0], + ); + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); + } + + switch (orderScenario.takerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + takerAssetData = assetProxyUtils.encodeERC20AssetData(this._zrxAddress); + break; + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + takerAssetData = assetProxyUtils.encodeERC20AssetData( + this._nonZrxERC20EighteenDecimalTokenAddresses[1], + ); + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetData = assetProxyUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]); + break; + case AssetDataScenario.ERC721: + takerAssetData = assetProxyUtils.encodeERC721AssetData( + this._erc721Token.address, + erc721TakerAssetIds[0], + ); + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); + } + + switch (orderScenario.makerAssetAmountScenario) { + case OrderAssetAmountScenario.Large: + switch (orderScenario.makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + makerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); + } + break; + case OrderAssetAmountScenario.Small: + switch (orderScenario.makerAssetDataScenario) { + case AssetDataScenario.ZRXFeeToken: + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + makerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); + } + break; + case OrderAssetAmountScenario.Zero: + makerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerAssetAmountScenario); + } + + switch (orderScenario.takerAssetAmountScenario) { + case OrderAssetAmountScenario.Large: + switch (orderScenario.takerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ZRXFeeToken: + takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + takerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); + } + break; + case OrderAssetAmountScenario.Small: + switch (orderScenario.takerAssetDataScenario) { + case AssetDataScenario.ERC20NonZRXEighteenDecimals: + case AssetDataScenario.ZRXFeeToken: + takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case AssetDataScenario.ERC20FiveDecimals: + takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; + break; + case AssetDataScenario.ERC721: + takerAssetAmount = ONE_NFT_UNIT; + break; + default: + throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); + } + break; + case OrderAssetAmountScenario.Zero: + takerAssetAmount = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerAssetAmountScenario); + } + + switch (orderScenario.makerFeeScenario) { + case OrderAssetAmountScenario.Large: + makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAssetAmountScenario.Small: + makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAssetAmountScenario.Zero: + makerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerFeeScenario); + } + + switch (orderScenario.takerFeeScenario) { + case OrderAssetAmountScenario.Large: + takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAssetAmountScenario.Small: + takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; + break; + case OrderAssetAmountScenario.Zero: + takerFee = new BigNumber(0); + break; + default: + throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerFeeScenario); + } + + switch (orderScenario.expirationTimeSecondsScenario) { + case ExpirationTimeSecondsScenario.InFuture: + expirationTimeSeconds = new BigNumber(2524604400); // Close to infinite + break; + case ExpirationTimeSecondsScenario.InPast: + expirationTimeSeconds = new BigNumber(0); // Jan 1, 1970 + break; + default: + throw errorUtils.spawnSwitchErr( + 'ExpirationTimeSecondsScenario', + orderScenario.expirationTimeSecondsScenario, + ); + } + + switch (orderScenario.takerScenario) { + case TakerScenario.CorrectlySpecified: + break; // noop since takerAddress is already specified + + case TakerScenario.IncorrectlySpecified: + const notTaker = this._userAddresses[3]; + takerAddress = notTaker; + break; + + case TakerScenario.Unspecified: + takerAddress = constants.NULL_ADDRESS; + break; + + default: + throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario); + } + + const order: Order = { + senderAddress: constants.NULL_ADDRESS, + makerAddress, + takerAddress, + makerFee, + takerFee, + makerAssetAmount, + takerAssetAmount, + makerAssetData, + takerAssetData, + salt: generatePseudoRandomSalt(), + exchangeAddress: this._exchangeAddress, + feeRecipientAddress, + expirationTimeSeconds, + }; + + return order; + } +} -- cgit v1.2.3 From f35af1fb6d141d23506d418a4110752595ff0b3d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 19 Jun 2018 17:53:16 +0200 Subject: Fix typo --- packages/contracts/src/utils/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index d71c14495..5be65fb1d 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -165,8 +165,8 @@ export enum OrderAssetAmountScenario { } export enum TakerScenario { - CorrectlySpecified = 'CORRECTLY_SPECFIED', - IncorrectlySpecified = 'INCORRECTLY_SPECFIED', + CorrectlySpecified = 'CORRECTLY_SPECIFIED', + IncorrectlySpecified = 'INCORRECTLY_SPECIFIED', Unspecified = 'UNSPECIFIED', } -- cgit v1.2.3 From 5541327968ad6f974a37c49057253746f738a709 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:24:09 +0200 Subject: Add ability for verbose logging --- packages/contracts/src/utils/core_combinatorial_utils.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index cdb8e579d..cf87ad36f 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -7,7 +7,7 @@ import { OrderValidationUtils, } from '@0xproject/order-utils'; import { AssetProxyId, Order, SignatureType, SignedOrder } from '@0xproject/types'; -import { BigNumber, errorUtils } from '@0xproject/utils'; +import { BigNumber, errorUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { BlockParamLiteral, LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; @@ -253,7 +253,11 @@ export class CoreCombinatorialUtils { this.exchangeWrapper = exchangeWrapper; this.assetWrapper = assetWrapper; } - public async testFillOrderScenarioAsync(provider: Provider, fillScenario: FillScenario): Promise { + public async testFillOrderScenarioAsync( + provider: Provider, + fillScenario: FillScenario, + isVerbose: boolean = false, + ): Promise { // 1. Generate order const order = this.orderFactory.generateOrder(fillScenario.orderScenario); @@ -304,6 +308,10 @@ export class CoreCombinatorialUtils { this.zrxAssetData, ); } catch (err) { + if (isVerbose) { + logUtils.log(`Expecting order to ${isFillFailureExpected ? 'fail' : 'succeed'} with:`); + logUtils.log(err); + } isFillFailureExpected = true; } -- cgit v1.2.3 From 632da71a8d7ab6f4ac64ace407543a8ff9f4d548 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:31:21 +0200 Subject: Add TS 2.7 numeric separators to improve readability --- packages/contracts/src/utils/order_factory_from_scenario.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/order_factory_from_scenario.ts b/packages/contracts/src/utils/order_factory_from_scenario.ts index 74c2d4fa2..8a5ded203 100644 --- a/packages/contracts/src/utils/order_factory_from_scenario.ts +++ b/packages/contracts/src/utils/order_factory_from_scenario.ts @@ -15,12 +15,12 @@ import { TakerScenario, } from './types'; -const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10000000000000000000); -const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5000000000000000000); -const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100000000000000000); -const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50000000000000000); -const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000); -const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500000); +const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10_000_000_000_000_000_000); +const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5_000_000_000_000_000_000); +const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100_000_000_000_000_000); +const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50_000_000_000_000_000); +const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000); +const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_000); const ONE_NFT_UNIT = new BigNumber(1); export class OrderFactoryFromScenario { -- cgit v1.2.3 From 32dea43d2e207ae235f3c7c869d307906a49660a Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:31:57 +0200 Subject: Remove unneeded explicit type def --- packages/contracts/src/utils/order_factory_from_scenario.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/order_factory_from_scenario.ts b/packages/contracts/src/utils/order_factory_from_scenario.ts index 8a5ded203..b150e59f6 100644 --- a/packages/contracts/src/utils/order_factory_from_scenario.ts +++ b/packages/contracts/src/utils/order_factory_from_scenario.ts @@ -256,7 +256,7 @@ export class OrderFactoryFromScenario { throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario); } - const order: Order = { + const order = { senderAddress: constants.NULL_ADDRESS, makerAddress, takerAddress, -- cgit v1.2.3 From 9bc481ff62cf9e4a60794000b8cab840405d63fa Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:36:57 +0200 Subject: Split balance and allowance amount types in prep of adding the "unlimited" allowance enum value --- .../src/utils/core_combinatorial_utils.ts | 67 +++++++++++----------- packages/contracts/src/utils/types.ts | 16 ++++-- 2 files changed, 45 insertions(+), 38 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index cf87ad36f..24ef333de 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -29,7 +29,9 @@ import { signingUtils } from '../utils/signing_utils'; import { SimpleAssetBalanceAndProxyAllowanceFetcher } from '../utils/simple_asset_balance_and_proxy_allowance_fetcher'; import { SimpleOrderFilledCancelledFetcher } from '../utils/simple_order_filled_cancelled_fetcher'; import { + AllowanceAmountScenario, AssetDataScenario, + BalanceAmountScenario, ExpirationTimeSecondsScenario, FeeRecipientAddressScenario, FillScenario, @@ -37,7 +39,6 @@ import { OrderScenario, TakerAssetFillAmountScenario, TakerScenario, - TokenAmountScenario, TraderStateScenario, } from '../utils/types'; @@ -192,16 +193,16 @@ export class CoreCombinatorialUtils { }, takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario, makerStateScenario: { - traderAssetBalance: TokenAmountScenario.Higher, - traderAssetAllowance: TokenAmountScenario.Higher, - zrxFeeBalance: TokenAmountScenario.Higher, - zrxFeeAllowance: TokenAmountScenario.Higher, + traderAssetBalance: BalanceAmountScenario.Higher, + traderAssetAllowance: AllowanceAmountScenario.Higher, + zrxFeeBalance: BalanceAmountScenario.Higher, + zrxFeeAllowance: AllowanceAmountScenario.Higher, }, takerStateScenario: { - traderAssetBalance: TokenAmountScenario.Higher, - traderAssetAllowance: TokenAmountScenario.Higher, - zrxFeeBalance: TokenAmountScenario.Higher, - zrxFeeAllowance: TokenAmountScenario.Higher, + traderAssetBalance: BalanceAmountScenario.Higher, + traderAssetAllowance: AllowanceAmountScenario.Higher, + zrxFeeBalance: BalanceAmountScenario.Higher, + zrxFeeAllowance: AllowanceAmountScenario.Higher, }, }; return fillScenario; @@ -547,10 +548,10 @@ export class CoreCombinatorialUtils { signedOrder.makerAssetAmount, ); switch (makerStateScenario.traderAssetBalance) { - case TokenAmountScenario.Higher: + case BalanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case BalanceAmountScenario.TooLow: if (makerAssetFillAmount.eq(0)) { throw new Error(`Cannot set makerAssetBalanceOfMaker TooLow if makerAssetFillAmount is 0`); } @@ -562,7 +563,7 @@ export class CoreCombinatorialUtils { ); break; - case TokenAmountScenario.Exact: + case BalanceAmountScenario.Exact: const exactBalance = makerAssetFillAmount; await this.assetWrapper.setBalanceAsync( signedOrder.makerAddress, @@ -584,10 +585,10 @@ export class CoreCombinatorialUtils { signedOrder.makerFee, ); switch (makerStateScenario.zrxFeeBalance) { - case TokenAmountScenario.Higher: + case BalanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case BalanceAmountScenario.TooLow: if (makerFee.eq(0)) { throw new Error(`Cannot set zrxAsserBalanceOfMaker TooLow if makerFee is 0`); } @@ -595,7 +596,7 @@ export class CoreCombinatorialUtils { await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, tooLowBalance); break; - case TokenAmountScenario.Exact: + case BalanceAmountScenario.Exact: const exactBalance = makerFee; await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, exactBalance); break; @@ -605,10 +606,10 @@ export class CoreCombinatorialUtils { } switch (makerStateScenario.traderAssetAllowance) { - case TokenAmountScenario.Higher: + case AllowanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case AllowanceAmountScenario.TooLow: const tooLowAllowance = makerAssetFillAmount.minus(1); await this.assetWrapper.setProxyAllowanceAsync( signedOrder.makerAddress, @@ -617,7 +618,7 @@ export class CoreCombinatorialUtils { ); break; - case TokenAmountScenario.Exact: + case AllowanceAmountScenario.Exact: const exactAllowance = makerAssetFillAmount; await this.assetWrapper.setProxyAllowanceAsync( signedOrder.makerAddress, @@ -634,10 +635,10 @@ export class CoreCombinatorialUtils { } switch (makerStateScenario.zrxFeeAllowance) { - case TokenAmountScenario.Higher: + case AllowanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case AllowanceAmountScenario.TooLow: const tooLowAllowance = makerFee.minus(1); await this.assetWrapper.setProxyAllowanceAsync( signedOrder.makerAddress, @@ -646,7 +647,7 @@ export class CoreCombinatorialUtils { ); break; - case TokenAmountScenario.Exact: + case AllowanceAmountScenario.Exact: const exactAllowance = makerFee; await this.assetWrapper.setProxyAllowanceAsync( signedOrder.makerAddress, @@ -663,10 +664,10 @@ export class CoreCombinatorialUtils { } switch (takerStateScenario.traderAssetBalance) { - case TokenAmountScenario.Higher: + case BalanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case BalanceAmountScenario.TooLow: if (takerAssetFillAmount.eq(0)) { throw new Error(`Cannot set takerAssetBalanceOfTaker TooLow if takerAssetFillAmount is 0`); } @@ -674,7 +675,7 @@ export class CoreCombinatorialUtils { await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, tooLowBalance); break; - case TokenAmountScenario.Exact: + case BalanceAmountScenario.Exact: const exactBalance = takerAssetFillAmount; await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, exactBalance); break; @@ -692,10 +693,10 @@ export class CoreCombinatorialUtils { signedOrder.takerFee, ); switch (takerStateScenario.zrxFeeBalance) { - case TokenAmountScenario.Higher: + case BalanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case BalanceAmountScenario.TooLow: if (takerFee.eq(0)) { throw new Error(`Cannot set zrxAssetBalanceOfTaker TooLow if takerFee is 0`); } @@ -703,7 +704,7 @@ export class CoreCombinatorialUtils { await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, tooLowBalance); break; - case TokenAmountScenario.Exact: + case BalanceAmountScenario.Exact: const exactBalance = takerFee; await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, exactBalance); break; @@ -713,10 +714,10 @@ export class CoreCombinatorialUtils { } switch (takerStateScenario.traderAssetAllowance) { - case TokenAmountScenario.Higher: + case AllowanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case AllowanceAmountScenario.TooLow: const tooLowAllowance = takerAssetFillAmount.minus(1); await this.assetWrapper.setProxyAllowanceAsync( this.takerAddress, @@ -725,7 +726,7 @@ export class CoreCombinatorialUtils { ); break; - case TokenAmountScenario.Exact: + case AllowanceAmountScenario.Exact: const exactAllowance = takerAssetFillAmount; await this.assetWrapper.setProxyAllowanceAsync( this.takerAddress, @@ -742,10 +743,10 @@ export class CoreCombinatorialUtils { } switch (takerStateScenario.zrxFeeAllowance) { - case TokenAmountScenario.Higher: + case AllowanceAmountScenario.Higher: break; // Noop since this is already the default - case TokenAmountScenario.TooLow: + case AllowanceAmountScenario.TooLow: const tooLowAllowance = takerFee.minus(1); await this.assetWrapper.setProxyAllowanceAsync( signedOrder.takerAddress, @@ -754,7 +755,7 @@ export class CoreCombinatorialUtils { ); break; - case TokenAmountScenario.Exact: + case AllowanceAmountScenario.Exact: const exactAllowance = takerFee; await this.assetWrapper.setProxyAllowanceAsync( signedOrder.takerAddress, diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 5be65fb1d..0b419d672 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -201,17 +201,23 @@ export interface OrderScenario { takerAssetDataScenario: AssetDataScenario; } -export enum TokenAmountScenario { +export enum BalanceAmountScenario { + Exact = 'EXACT', + TooLow = 'TOO_LOW', + Higher = 'HIGHER', +} + +export enum AllowanceAmountScenario { Exact = 'EXACT', TooLow = 'TOO_LOW', Higher = 'HIGHER', } export interface TraderStateScenario { - traderAssetBalance: TokenAmountScenario; - traderAssetAllowance: TokenAmountScenario; - zrxFeeBalance: TokenAmountScenario; - zrxFeeAllowance: TokenAmountScenario; + traderAssetBalance: BalanceAmountScenario; + traderAssetAllowance: AllowanceAmountScenario; + zrxFeeBalance: BalanceAmountScenario; + zrxFeeAllowance: AllowanceAmountScenario; } export interface FillScenario { -- cgit v1.2.3 From 0bbdbc9e63fbd73158c1ffd76eb3f3e4d0660598 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:55:28 +0200 Subject: Rename for clarity --- packages/contracts/src/utils/asset_wrapper.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index 2eb54f290..f86c0bc23 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -29,8 +29,8 @@ export class AssetWrapper { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { case constants.ERC20_PROXY_ID: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const balance = await assetWrapper.getBalanceAsync(userAddress, assetData); + const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData); return balance; } case constants.ERC721_PROXY_ID: { @@ -52,8 +52,8 @@ export class AssetWrapper { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { case constants.ERC20_PROXY_ID: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - await assetWrapper.setBalanceAsync(userAddress, assetData, desiredBalance); + const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + await erc20Wrapper.setBalanceAsync(userAddress, assetData, desiredBalance); return; } case constants.ERC721_PROXY_ID: { @@ -98,8 +98,8 @@ export class AssetWrapper { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { case constants.ERC20_PROXY_ID: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const allowance = await assetWrapper.getProxyAllowanceAsync(userAddress, assetData); + const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData); return allowance; } case constants.ERC721_PROXY_ID: { @@ -129,8 +129,8 @@ export class AssetWrapper { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { case constants.ERC20_PROXY_ID: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - await assetWrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); + const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; + await erc20Wrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); return; } case constants.ERC721_PROXY_ID: { -- cgit v1.2.3 From 3fab40efe553446770c8858afd0020f613ca4d4c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:55:45 +0200 Subject: Add noop conditionals for clarity --- packages/contracts/src/utils/asset_wrapper.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index f86c0bc23..11697eca8 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -87,6 +87,11 @@ export class AssetWrapper { // Burn token await erc721Wrapper.burnAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress); return; + } else if ( + (userAddress !== tokenOwner && desiredBalance.eq(0)) || + (tokenOwner === userAddress && desiredBalance.eq(1)) + ) { + return; // noop } break; } @@ -176,6 +181,11 @@ export class AssetWrapper { assetProxyData.tokenAddress, assetProxyData.tokenId, ); + } else if ( + (!isProxyApproved && desiredAllowance.eq(0)) || + (isProxyApproved && desiredAllowance.eq(1)) + ) { + return; // noop } break; -- cgit v1.2.3 From fb7d425244fd754c478f432c5a64d52917071fbc Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 13:56:27 +0200 Subject: Add support for setting allowance to unlimited --- packages/contracts/src/utils/asset_wrapper.ts | 31 ++++++++++++++++++++------ packages/contracts/src/utils/erc721_wrapper.ts | 11 +++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index 11697eca8..fd543621f 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -139,8 +139,14 @@ export class AssetWrapper { return; } case constants.ERC721_PROXY_ID: { - if (!desiredAllowance.eq(0) && !desiredAllowance.eq(1)) { - throw new Error(`Allowance for ERC721 token can only be set to 0 or 1. Got: ${desiredAllowance}`); + if ( + !desiredAllowance.eq(0) && + !desiredAllowance.eq(1) && + !desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS) + ) { + throw new Error( + `Allowance for ERC721 token can only be set to 0, 1 or 2^256-1. Got: ${desiredAllowance}`, + ); } const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); @@ -161,11 +167,22 @@ export class AssetWrapper { assetProxyData.tokenAddress, assetProxyData.tokenId, ); - // HACK: We do not currently support ApprovedForAll when setting proxy allowance - // This was intentional since unsetting ApprovedForAll, will unset approval for unrelated - // tokens other then the one specified in the call to this method. - if (isProxyApprovedForAll) { - throw new Error(`We don't currently support the use of "approveAll" functionality for ERC721.`); + if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + const isApproved = true; + await erc721Wrapper.approveProxyForAllAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + isApproved, + ); + } else if (isProxyApprovedForAll && desiredAllowance.eq(0)) { + const isApproved = false; + await erc721Wrapper.approveProxyForAllAsync( + assetProxyData.tokenAddress, + assetProxyData.tokenId, + isApproved, + ); + } else if (isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + return; // Noop } const isProxyApproved = await erc721Wrapper.isProxyApprovedAsync( diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index 7da3b6781..6df9fa12e 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -88,6 +88,17 @@ export class ERC721Wrapper { const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; await this.approveAsync(proxyAddress, tokenAddress, tokenId); } + public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.setApprovalForAll.sendTransactionAsync(proxyAddress, isApproved, { + from: tokenOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise { const tokenContract = this._getTokenContractFromAssetData(tokenAddress); const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); -- cgit v1.2.3 From 5c0183c71ef9f988c6a7c799c177df53c222acb3 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 14:08:56 +0200 Subject: Fix merge variable name issue --- packages/contracts/src/utils/core_combinatorial_utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 24ef333de..4d6f3b965 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -263,7 +263,7 @@ export class CoreCombinatorialUtils { const order = this.orderFactory.generateOrder(fillScenario.orderScenario); // 2. Sign order - const orderHashBuff = orderHashUtils.getOrderHashBuff(order); + const orderHashBuff = orderHashUtils.getOrderHashBuffer(order); const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign); const signedOrder = { ...order, -- cgit v1.2.3 From 3ce449e16739896f81b171d130afbb5774829d64 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 19:12:31 +0200 Subject: Improve verbose logging --- packages/contracts/src/utils/core_combinatorial_utils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 4d6f3b965..f1a5599ef 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -308,12 +308,15 @@ export class CoreCombinatorialUtils { this.takerAddress, this.zrxAssetData, ); + if (isVerbose) { + logUtils.log(`Expecting fillOrder to succeed.`); + } } catch (err) { + isFillFailureExpected = true; if (isVerbose) { - logUtils.log(`Expecting order to ${isFillFailureExpected ? 'fail' : 'succeed'} with:`); + logUtils.log(`Expecting fillOrder to fail with:`); logUtils.log(err); } - isFillFailureExpected = true; } // 6. Fill the order -- cgit v1.2.3 From 5bfdffda1155e306b17eee0a4e60320c3433d5c4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 20 Jun 2018 19:14:04 +0200 Subject: Add support for approveAll in assetWrapper and fillOrderScenarios --- packages/contracts/src/utils/asset_wrapper.ts | 12 +++++--- .../src/utils/core_combinatorial_utils.ts | 32 ++++++++++++++++++++++ packages/contracts/src/utils/types.ts | 1 + 3 files changed, 41 insertions(+), 4 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index fd543621f..9c683054d 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -110,16 +110,20 @@ export class AssetWrapper { case constants.ERC721_PROXY_ID: { const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); - const isProxyApproved = await assetWrapper.isProxyApprovedAsync( + const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync( + userAddress, erc721ProxyData.tokenAddress, erc721ProxyData.tokenId, ); - const isProxyApprovedForAllAsync = await assetWrapper.isProxyApprovedForAllAsync( - userAddress, + if (isProxyApprovedForAll) { + return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + } + + const isProxyApproved = await assetWrapper.isProxyApprovedAsync( erc721ProxyData.tokenAddress, erc721ProxyData.tokenId, ); - const allowance = isProxyApproved || isProxyApprovedForAllAsync ? new BigNumber(1) : new BigNumber(0); + const allowance = isProxyApproved ? new BigNumber(1) : new BigNumber(0); return allowance; } default: diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index f1a5599ef..7e9d18e46 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -630,6 +630,14 @@ export class CoreCombinatorialUtils { ); break; + case AllowanceAmountScenario.Unlimited: + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + signedOrder.makerAssetData, + constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); + break; + default: throw errorUtils.spawnSwitchErr( 'makerStateScenario.traderAssetAllowance', @@ -659,6 +667,14 @@ export class CoreCombinatorialUtils { ); break; + case AllowanceAmountScenario.Unlimited: + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.makerAddress, + this.zrxAssetData, + constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); + break; + default: throw errorUtils.spawnSwitchErr( 'makerStateScenario.zrxFeeAllowance', @@ -738,6 +754,14 @@ export class CoreCombinatorialUtils { ); break; + case AllowanceAmountScenario.Unlimited: + await this.assetWrapper.setProxyAllowanceAsync( + this.takerAddress, + signedOrder.takerAssetData, + constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); + break; + default: throw errorUtils.spawnSwitchErr( 'takerStateScenario.traderAssetAllowance', @@ -767,6 +791,14 @@ export class CoreCombinatorialUtils { ); break; + case AllowanceAmountScenario.Unlimited: + await this.assetWrapper.setProxyAllowanceAsync( + signedOrder.takerAddress, + this.zrxAssetData, + constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); + break; + default: throw errorUtils.spawnSwitchErr( 'takerStateScenario.zrxFeeAllowance', diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 0b419d672..7d9217c50 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -211,6 +211,7 @@ export enum AllowanceAmountScenario { Exact = 'EXACT', TooLow = 'TOO_LOW', Higher = 'HIGHER', + Unlimited = 'UNLIMITED', } export interface TraderStateScenario { -- cgit v1.2.3 From ad67a6add54cc31f4b888dbbfe70fed75b743745 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 25 Jun 2018 13:51:00 +0200 Subject: Check revert reasons in declarative and combinatorial tests --- packages/contracts/src/utils/core_combinatorial_utils.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index 7e9d18e46..aea9a65e7 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -16,7 +16,7 @@ import 'make-promises-safe'; import { ExchangeContract, FillContractEventArgs } from '../generated_contract_wrappers/exchange'; import { artifacts } from '../utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; import { AssetWrapper } from '../utils/asset_wrapper'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; @@ -298,7 +298,7 @@ export class CoreCombinatorialUtils { const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); - let isFillFailureExpected = false; + let fillRevertReasonIfExists; try { await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( exchangeTransferSimulator, @@ -312,7 +312,7 @@ export class CoreCombinatorialUtils { logUtils.log(`Expecting fillOrder to succeed.`); } } catch (err) { - isFillFailureExpected = true; + fillRevertReasonIfExists = err.message; if (isVerbose) { logUtils.log(`Expecting fillOrder to fail with:`); logUtils.log(err); @@ -324,7 +324,7 @@ export class CoreCombinatorialUtils { signedOrder, takerAssetFillAmount, lazyStore, - isFillFailureExpected, + fillRevertReasonIfExists, provider, ); } @@ -332,12 +332,13 @@ export class CoreCombinatorialUtils { signedOrder: SignedOrder, takerAssetFillAmount: BigNumber, lazyStore: BalanceAndProxyAllowanceLazyStore, - isFillFailureExpected: boolean, + fillRevertReasonIfExists: string | undefined, provider: Provider, ): Promise { - if (isFillFailureExpected) { - return expectRevertOrAlwaysFailingTransactionAsync( + if (!_.isUndefined(fillRevertReasonIfExists)) { + return expectRevertReasonOrAlwaysFailingTransactionAsync( this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), + fillRevertReasonIfExists, ); } -- cgit v1.2.3 From 1134ff107542d9014b195b6dc6ce6040752c92e3 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 25 Jun 2018 20:17:00 +0200 Subject: Fix tslint issues --- packages/contracts/src/utils/asset_wrapper.ts | 2 -- packages/contracts/src/utils/core_combinatorial_utils.ts | 14 ++------------ packages/contracts/src/utils/erc721_wrapper.ts | 3 +-- 3 files changed, 3 insertions(+), 16 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index 9c683054d..d5ce8cf1e 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -113,7 +113,6 @@ export class AssetWrapper { const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync( userAddress, erc721ProxyData.tokenAddress, - erc721ProxyData.tokenId, ); if (isProxyApprovedForAll) { return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; @@ -169,7 +168,6 @@ export class AssetWrapper { const isProxyApprovedForAll = await erc721Wrapper.isProxyApprovedForAllAsync( userAddress, assetProxyData.tokenAddress, - assetProxyData.tokenId, ); if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { const isApproved = true; diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index aea9a65e7..a2d2a500b 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -6,11 +6,11 @@ import { OrderStateUtils, OrderValidationUtils, } from '@0xproject/order-utils'; -import { AssetProxyId, Order, SignatureType, SignedOrder } from '@0xproject/types'; +import { AssetProxyId, SignatureType, SignedOrder } from '@0xproject/types'; import { BigNumber, errorUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; -import { BlockParamLiteral, LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; +import { LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; import * as _ from 'lodash'; import 'make-promises-safe'; @@ -36,7 +36,6 @@ import { FeeRecipientAddressScenario, FillScenario, OrderAssetAmountScenario, - OrderScenario, TakerAssetFillAmountScenario, TakerScenario, TraderStateScenario, @@ -290,7 +289,6 @@ export class CoreCombinatorialUtils { fillScenario.takerStateScenario, signedOrder, takerAssetFillAmount, - balanceAndProxyAllowanceFetcher, ); // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected? @@ -325,7 +323,6 @@ export class CoreCombinatorialUtils { takerAssetFillAmount, lazyStore, fillRevertReasonIfExists, - provider, ); } private async _fillOrderAndAssertOutcomeAsync( @@ -333,7 +330,6 @@ export class CoreCombinatorialUtils { takerAssetFillAmount: BigNumber, lazyStore: BalanceAndProxyAllowanceLazyStore, fillRevertReasonIfExists: string | undefined, - provider: Provider, ): Promise { if (!_.isUndefined(fillRevertReasonIfExists)) { return expectRevertReasonOrAlwaysFailingTransactionAsync( @@ -375,11 +371,6 @@ export class CoreCombinatorialUtils { signedOrder.makerAssetAmount, ); - const beforeMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync( - makerAddress, - makerAssetData, - ); - // - Let's fill the order! const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount, @@ -544,7 +535,6 @@ export class CoreCombinatorialUtils { takerStateScenario: TraderStateScenario, signedOrder: SignedOrder, takerAssetFillAmount: BigNumber, - balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, ): Promise { const makerAssetFillAmount = orderUtils.getPartialAmount( takerAssetFillAmount, diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index 6df9fa12e..e83e845a0 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -1,4 +1,4 @@ -import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { generatePseudoRandomSalt } from '@0xproject/order-utils'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Provider } from 'ethereum-types'; @@ -155,7 +155,6 @@ export class ERC721Wrapper { public async isProxyApprovedForAllAsync( userAddress: string, tokenAddress: string, - tokenId: BigNumber, ): Promise { this._validateProxyContractExistsOrThrow(); const tokenContract = this._getTokenContractFromAssetData(tokenAddress); -- cgit v1.2.3 From 8064914bb7f226c98d62357e29581238f0f765e4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 25 Jun 2018 23:17:56 +0200 Subject: Prettier fixes --- packages/contracts/src/utils/erc721_wrapper.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index e83e845a0..0ad2fc7d7 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -152,10 +152,7 @@ export class ERC721Wrapper { const isOwner = tokenOwner === userAddress; return isOwner; } - public async isProxyApprovedForAllAsync( - userAddress: string, - tokenAddress: string, - ): Promise { + public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise { this._validateProxyContractExistsOrThrow(); const tokenContract = this._getTokenContractFromAssetData(tokenAddress); const operator = (this._proxyContract as ERC721ProxyContract).address; -- cgit v1.2.3 From 105b9273975b34d46dc98254846d2b31990d9d9a Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 26 Jun 2018 08:43:37 +0200 Subject: Fix merge issues --- packages/contracts/src/utils/asset_wrapper.ts | 19 ++++++++++--------- .../contracts/src/utils/core_combinatorial_utils.ts | 2 +- packages/contracts/src/utils/erc20_wrapper.ts | 6 +++--- packages/contracts/src/utils/erc721_wrapper.ts | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/asset_wrapper.ts b/packages/contracts/src/utils/asset_wrapper.ts index d5ce8cf1e..a7f91f413 100644 --- a/packages/contracts/src/utils/asset_wrapper.ts +++ b/packages/contracts/src/utils/asset_wrapper.ts @@ -1,4 +1,5 @@ import { assetProxyUtils } from '@0xproject/order-utils'; +import { AssetProxyId } from '@0xproject/types'; import { BigNumber, errorUtils } from '@0xproject/utils'; import * as _ from 'lodash'; @@ -9,7 +10,7 @@ import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; interface ProxyIdToAssetWrappers { - [proxyId: number]: AbstractAssetWrapper; + [proxyId: string]: AbstractAssetWrapper; } /** @@ -28,12 +29,12 @@ export class AssetWrapper { public async getBalanceAsync(userAddress: string, assetData: string): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { - case constants.ERC20_PROXY_ID: { + case AssetProxyId.ERC20: { const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData); return balance; } - case constants.ERC721_PROXY_ID: { + case AssetProxyId.ERC721: { const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const assetProxyData = assetProxyUtils.decodeERC721AssetData(assetData); const isOwner = await assetWrapper.isOwnerAsync( @@ -51,12 +52,12 @@ export class AssetWrapper { public async setBalanceAsync(userAddress: string, assetData: string, desiredBalance: BigNumber): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { - case constants.ERC20_PROXY_ID: { + case AssetProxyId.ERC20: { const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; await erc20Wrapper.setBalanceAsync(userAddress, assetData, desiredBalance); return; } - case constants.ERC721_PROXY_ID: { + case AssetProxyId.ERC721: { if (!desiredBalance.eq(0) && !desiredBalance.eq(1)) { throw new Error(`Balance for ERC721 token can only be set to 0 or 1. Got: ${desiredBalance}`); } @@ -102,12 +103,12 @@ export class AssetWrapper { public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { - case constants.ERC20_PROXY_ID: { + case AssetProxyId.ERC20: { const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData); return allowance; } - case constants.ERC721_PROXY_ID: { + case AssetProxyId.ERC721: { const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; const erc721ProxyData = assetProxyUtils.decodeERC721AssetData(assetData); const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync( @@ -136,12 +137,12 @@ export class AssetWrapper { ): Promise { const proxyId = assetProxyUtils.decodeAssetDataId(assetData); switch (proxyId) { - case constants.ERC20_PROXY_ID: { + case AssetProxyId.ERC20: { const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; await erc20Wrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); return; } - case constants.ERC721_PROXY_ID: { + case AssetProxyId.ERC721: { if ( !desiredAllowance.eq(0) && !desiredAllowance.eq(1) && diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index a2d2a500b..a775c619f 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -515,7 +515,7 @@ export class CoreCombinatorialUtils { const takerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.takerAssetData); const makerAssetProxyId = assetProxyUtils.decodeAssetDataId(signedOrder.makerAssetData); const isEitherAssetERC721 = - takerAssetProxyId === constants.ERC721_PROXY_ID || makerAssetProxyId === constants.ERC721_PROXY_ID; + takerAssetProxyId === AssetProxyId.ERC721 || makerAssetProxyId === AssetProxyId.ERC721; if (isEitherAssetERC721) { throw new Error( 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.', diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index 6dd717f4a..652f29726 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -19,7 +19,7 @@ export class ERC20Wrapper { private _provider: Provider; private _dummyTokenContracts: DummyERC20TokenContract[]; private _proxyContract?: ERC20ProxyContract; - private _proxyIdIfExists?: number; + private _proxyIdIfExists?: string; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._dummyTokenContracts = []; this._web3Wrapper = new Web3Wrapper(provider); @@ -55,9 +55,9 @@ export class ERC20Wrapper { this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; } - public getProxyId(): number { + public getProxyId(): string { this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as number; + return this._proxyIdIfExists as string; } public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index 0ad2fc7d7..309135ae4 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -19,7 +19,7 @@ export class ERC721Wrapper { private _provider: Provider; private _dummyTokenContracts: DummyERC721TokenContract[]; private _proxyContract?: ERC721ProxyContract; - private _proxyIdIfExists?: number; + private _proxyIdIfExists?: string; private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); @@ -51,9 +51,9 @@ export class ERC721Wrapper { this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; } - public getProxyId(): number { + public getProxyId(): string { this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as number; + return this._proxyIdIfExists as string; } public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); -- cgit v1.2.3 From 2a82807be4099460173ce885867896a8755091b2 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 26 Jun 2018 19:16:57 +0200 Subject: Fix type issue --- packages/contracts/src/utils/core_combinatorial_utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index a775c619f..becf19c06 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -6,7 +6,7 @@ import { OrderStateUtils, OrderValidationUtils, } from '@0xproject/order-utils'; -import { AssetProxyId, SignatureType, SignedOrder } from '@0xproject/types'; +import { AssetProxyId, RevertReason, SignatureType, SignedOrder } from '@0xproject/types'; import { BigNumber, errorUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; @@ -329,7 +329,7 @@ export class CoreCombinatorialUtils { signedOrder: SignedOrder, takerAssetFillAmount: BigNumber, lazyStore: BalanceAndProxyAllowanceLazyStore, - fillRevertReasonIfExists: string | undefined, + fillRevertReasonIfExists: RevertReason | undefined, ): Promise { if (!_.isUndefined(fillRevertReasonIfExists)) { return expectRevertReasonOrAlwaysFailingTransactionAsync( -- cgit v1.2.3 From f49a5072972296677cc19ab5d5354175b8f8287b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 28 Jun 2018 09:13:56 +0200 Subject: Add missing awaitTransactionSuccessAsync calls --- packages/contracts/src/utils/erc20_wrapper.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index 652f29726..451f16513 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -90,9 +90,11 @@ export class ERC20Wrapper { } public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { const tokenContract = this._getTokenContractFromAssetData(assetData); - await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, { - from: this._contractOwnerAddress, - }); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, { + from: this._contractOwnerAddress, + }), + ); } public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { const tokenContract = this._getTokenContractFromAssetData(assetData); @@ -103,9 +105,11 @@ export class ERC20Wrapper { public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { const tokenContract = this._getTokenContractFromAssetData(assetData); const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; - await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, { - from: userAddress, - }); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, { + from: userAddress, + }), + ); } public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); -- cgit v1.2.3 From b56baefaa66bb37ba1ea6c0dd487b2caf1ef44bd Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 28 Jun 2018 09:34:13 +0200 Subject: Add await time constant --- packages/contracts/src/utils/erc20_wrapper.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index 451f16513..7f00e2061 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -94,6 +94,7 @@ export class ERC20Wrapper { await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, { from: this._contractOwnerAddress, }), + constants.AWAIT_TRANSACTION_MINED_MS, ); } public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { @@ -109,6 +110,7 @@ export class ERC20Wrapper { await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, { from: userAddress, }), + constants.AWAIT_TRANSACTION_MINED_MS, ); } public async getBalancesAsync(): Promise { -- cgit v1.2.3 From 646927962a9147272d8e3dcc95e2217de205280b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 28 Jun 2018 10:43:37 +0200 Subject: Reduce the userAddresses to the individual addresses actually used by tests, as well as only deploy the number of ERC20 tokens needed for each test suite --- packages/contracts/src/utils/core_combinatorial_utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/core_combinatorial_utils.ts b/packages/contracts/src/utils/core_combinatorial_utils.ts index becf19c06..5b725fbe3 100644 --- a/packages/contracts/src/utils/core_combinatorial_utils.ts +++ b/packages/contracts/src/utils/core_combinatorial_utils.ts @@ -55,7 +55,8 @@ export async function coreCombinatorialUtilsFactoryAsync( web3Wrapper: Web3Wrapper, txDefaults: Partial, ): Promise { - const userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const userAddresses = _.slice(accounts, 0, 5); const [ownerAddress, makerAddress, takerAddress] = userAddresses; const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)]; -- cgit v1.2.3 From 4fe626904337290774e39f3aba143fa776785269 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 28 Jun 2018 10:45:28 +0200 Subject: Remove unused constants --- packages/contracts/src/utils/constants.ts | 2 -- 1 file changed, 2 deletions(-) (limited to 'packages/contracts/src/utils') diff --git a/packages/contracts/src/utils/constants.ts b/packages/contracts/src/utils/constants.ts index 1e7b731dc..2b2bd2425 100644 --- a/packages/contracts/src/utils/constants.ts +++ b/packages/contracts/src/utils/constants.ts @@ -19,8 +19,6 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [ export const constants = { INVALID_OPCODE: 'invalid opcode', REVERT: 'revert', - ERC20_PROXY_ID: 1, - ERC721_PROXY_ID: 2, TESTRPC_NETWORK_ID: 50, // Note(albrow): In practice V8 and most other engines limit the minimum // interval for setInterval to 10ms. We still set it to 0 here in order to -- cgit v1.2.3