diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2018-11-22 21:52:25 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2018-12-03 18:31:53 +0800 |
commit | 4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004 (patch) | |
tree | 43cad9046ecc4c9e59e9d9743c6f076878881037 /packages/contracts/test/utils | |
parent | 502e9c7be48caafd7725451789f896efdaf17dac (diff) | |
download | dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.gz dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.bz2 dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.lz dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.xz dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.tar.zst dexon-sol-tools-4668b0732ce4b62b3b7d19ea4e155a6d3c4e6004.zip |
Move packages/contracts to contracts/core
Diffstat (limited to 'packages/contracts/test/utils')
31 files changed, 0 insertions, 4230 deletions
diff --git a/packages/contracts/test/utils/abstract_asset_wrapper.ts b/packages/contracts/test/utils/abstract_asset_wrapper.ts deleted file mode 100644 index 4b56a8502..000000000 --- a/packages/contracts/test/utils/abstract_asset_wrapper.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class AbstractAssetWrapper { - public abstract getProxyId(): string; -} diff --git a/packages/contracts/test/utils/address_utils.ts b/packages/contracts/test/utils/address_utils.ts deleted file mode 100644 index 634da0c16..000000000 --- a/packages/contracts/test/utils/address_utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { crypto } from '@0x/order-utils/lib/src/crypto'; - -export const addressUtils = { - generatePseudoRandomAddress(): string { - const randomBigNum = generatePseudoRandomSalt(); - const randomBuff = crypto.solSHA3([randomBigNum]); - const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`; - return randomAddress; - }, -}; diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts deleted file mode 100644 index 5b1cedfcc..000000000 --- a/packages/contracts/test/utils/assertions.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { RevertReason } from '@0x/types'; -import { logUtils } from '@0x/utils'; -import { NodeType } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { web3Wrapper } from './web3_wrapper'; - -const expect = chai.expect; - -let nodeType: NodeType | undefined; - -// Represents the return value of a `sendTransaction` call. The Promise should -// resolve with either a transaction receipt or a transaction hash. -export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>; - -/** - * Returns ganacheError if the backing Ethereum node is Ganache and gethError - * if it is Geth. - * @param ganacheError the error to be returned if the backing node is Ganache. - * @param gethError the error to be returned if the backing node is Geth. - * @returns either the given ganacheError or gethError depending on the backing - * node. - */ -async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> { - if (_.isUndefined(nodeType)) { - nodeType = await web3Wrapper.getNodeTypeAsync(); - } - switch (nodeType) { - case NodeType.Ganache: - return ganacheError; - case NodeType.Geth: - return gethError; - default: - throw new Error(`Unknown node type: ${nodeType}`); - } -} - -async function _getInsufficientFundsErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds'); -} - -async function _getTransactionFailedErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError('revert', 'always failing transaction'); -} - -async function _getContractCallFailedErrorMessageAsync(): Promise<string> { - return _getGanacheOrGethError('revert', 'Contract call failed'); -} - -/** - * Returns the expected error message for an 'invalid opcode' resulting from a - * contract call. The exact error message depends on the backing Ethereum node. - */ -export async function getInvalidOpcodeErrorMessageForCallAsync(): Promise<string> { - return _getGanacheOrGethError('invalid opcode', 'Contract call failed'); -} - -/** - * Returns the expected error message for the given revert reason resulting from - * a sendTransaction call. The exact error message depends on the backing - * Ethereum node and whether it supports revert reasons. - * @param reason a specific revert reason. - * @returns the expected error message. - */ -export async function getRevertReasonOrErrorMessageForSendTransactionAsync(reason: RevertReason): Promise<string> { - return _getGanacheOrGethError(reason, 'always failing transaction'); -} - -/** - * Rejects if the given Promise does not reject with an error indicating - * insufficient funds. - * @param p a promise resulting from a contract call or sendTransaction call. - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getInsufficientFundsErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} - -/** - * Resolves if the the sendTransaction call fails with the given revert reason. - * However, since Geth does not support revert reasons for sendTransaction, this - * falls back to expectTransactionFailedWithoutReasonAsync if the backing - * Ethereum node is Geth. - * @param p a Promise resulting from a sendTransaction call - * @param reason a specific revert reason - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> { - // HACK(albrow): This dummy `catch` should not be necessary, but if you - // remove it, there is an uncaught exception and the Node process will - // forcibly exit. It's possible this is a false positive in - // make-promises-safe. - p.catch(e => { - _.noop(e); - }); - - if (_.isUndefined(nodeType)) { - nodeType = await web3Wrapper.getNodeTypeAsync(); - } - switch (nodeType) { - case NodeType.Ganache: - return expect(p).to.be.rejectedWith(reason); - case NodeType.Geth: - logUtils.warn( - 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.', - ); - return expectTransactionFailedWithoutReasonAsync(p); - default: - throw new Error(`Unknown node type: ${nodeType}`); - } -} - -/** - * Resolves if the transaction fails without a revert reason, or if the - * corresponding transactionReceipt has a status of 0 or '0', indicating - * failure. - * @param p a Promise resulting from a sendTransaction call - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise<void> { - return p - .then(async result => { - let txReceiptStatus: TransactionReceiptStatus; - if (_.isString(result)) { - // Result is a txHash. We need to make a web3 call to get the - // receipt, then get the status from the receipt. - const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result); - txReceiptStatus = txReceipt.status; - } else if ('status' in result) { - // Result is a transaction receipt, so we can get the status - // directly. - txReceiptStatus = result.status; - } else { - throw new Error('Unexpected result type: ' + typeof result); - } - expect(_.toString(txReceiptStatus)).to.equal( - '0', - 'Expected transaction to fail but receipt had a non-zero status, indicating success', - ); - }) - .catch(async err => { - // If the promise rejects, we expect a specific error message, - // depending on the backing Ethereum node type. - const errMessage = await _getTransactionFailedErrorMessageAsync(); - expect(err.message).to.include(errMessage); - }); -} - -/** - * Resolves if the the contract call fails with the given revert reason. - * @param p a Promise resulting from a contract call - * @param reason a specific revert reason - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCallFailedAsync<T>(p: Promise<T>, reason: RevertReason): Promise<void> { - return expect(p).to.be.rejectedWith(reason); -} - -/** - * Resolves if the contract call fails without a revert reason. - * @param p a Promise resulting from a contract call - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getContractCallFailedErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} - -/** - * Resolves if the contract creation/deployment fails without a revert reason. - * @param p a Promise resulting from a contract creation/deployment - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCreationFailedAsync<T>( - p: sendTransactionResult, - reason: RevertReason, -): Promise<void> { - return expectTransactionFailedAsync(p, reason); -} - -/** - * Resolves if the contract creation/deployment fails without a revert reason. - * @param p a Promise resulting from a contract creation/deployment - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export async function expectContractCreationFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> { - const errMessage = await _getTransactionFailedErrorMessageAsync(); - return expect(p).to.be.rejectedWith(errMessage); -} diff --git a/packages/contracts/test/utils/asset_wrapper.ts b/packages/contracts/test/utils/asset_wrapper.ts deleted file mode 100644 index 4e7696066..000000000 --- a/packages/contracts/test/utils/asset_wrapper.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { assetDataUtils } from '@0x/order-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, errorUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractAssetWrapper } from './abstract_asset_wrapper'; -import { constants } from './constants'; -import { ERC20Wrapper } from './erc20_wrapper'; -import { ERC721Wrapper } from './erc721_wrapper'; - -interface ProxyIdToAssetWrappers { - [proxyId: string]: 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 readonly _proxyIdToAssetWrappers: ProxyIdToAssetWrappers; - constructor(assetWrappers: AbstractAssetWrapper[]) { - this._proxyIdToAssetWrappers = {}; - _.each(assetWrappers, assetWrapper => { - const proxyId = assetWrapper.getProxyId(); - this._proxyIdToAssetWrappers[proxyId] = assetWrapper; - }); - } - public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { - const proxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData); - return balance; - } - case AssetProxyId.ERC721: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - const assetProxyData = assetDataUtils.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<void> { - const proxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - await erc20Wrapper.setBalanceAsync(userAddress, assetData, desiredBalance); - return; - } - 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}`); - } - const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - const assetProxyData = assetDataUtils.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 (tokenOwner === userAddress && desiredBalance.eq(0)) { - // Transfer token to someone else - const userAddresses = await (erc721Wrapper as any)._web3Wrapper.getAvailableAddressesAsync(); - const nonOwner = _.find(userAddresses, a => a !== userAddress); - await erc721Wrapper.transferFromAsync( - assetProxyData.tokenAddress, - assetProxyData.tokenId, - tokenOwner, - nonOwner, - ); - return; - } else if ( - (userAddress !== tokenOwner && desiredBalance.eq(0)) || - (tokenOwner === userAddress && desiredBalance.eq(1)) - ) { - return; // noop - } - break; - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { - const proxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData); - return allowance; - } - case AssetProxyId.ERC721: { - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - const erc721ProxyData = assetDataUtils.decodeERC721AssetData(assetData); - const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync( - userAddress, - erc721ProxyData.tokenAddress, - ); - if (isProxyApprovedForAll) { - return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - } - - const isProxyApproved = await assetWrapper.isProxyApprovedAsync( - erc721ProxyData.tokenAddress, - erc721ProxyData.tokenId, - ); - const allowance = isProxyApproved ? new BigNumber(1) : new BigNumber(0); - return allowance; - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async setProxyAllowanceAsync( - userAddress: string, - assetData: string, - desiredAllowance: BigNumber, - ): Promise<void> { - const proxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - await erc20Wrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance); - return; - } - case AssetProxyId.ERC721: { - 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 = assetDataUtils.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, - ); - 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( - assetProxyData.tokenAddress, - assetProxyData.tokenId, - ); - 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); - } - } -} diff --git a/packages/contracts/test/utils/block_timestamp.ts b/packages/contracts/test/utils/block_timestamp.ts deleted file mode 100644 index 66c13eed1..000000000 --- a/packages/contracts/test/utils/block_timestamp.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { web3Wrapper } from './web3_wrapper'; - -let firstAccount: string | undefined; - -/** - * Increases time by the given number of seconds and then mines a block so that - * the current block timestamp has the offset applied. - * @param seconds the number of seconds by which to incrase the time offset. - * @returns a new Promise which will resolve with the new total time offset or - * reject if the time could not be increased. - */ -export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> { - if (_.isUndefined(firstAccount)) { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - firstAccount = accounts[0]; - } - - const offset = await web3Wrapper.increaseTimeAsync(seconds); - // Note: we need to send a transaction after increasing time so - // that a block is actually mined. The contract looks at the - // last mined block for the timestamp. - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - - return offset; -} - -/** - * Returns the timestamp of the latest block in seconds since the Unix epoch. - * @returns a new Promise which will resolve with the timestamp in seconds. - */ -export async function getLatestBlockTimestampAsync(): Promise<number> { - const currentBlockIfExists = await web3Wrapper.getBlockIfExistsAsync('latest'); - if (_.isUndefined(currentBlockIfExists)) { - throw new Error(`Unable to fetch latest block.`); - } - return currentBlockIfExists.timestamp; -} diff --git a/packages/contracts/test/utils/chai_setup.ts b/packages/contracts/test/utils/chai_setup.ts deleted file mode 100644 index 1a8733093..000000000 --- a/packages/contracts/test/utils/chai_setup.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as chai from 'chai'; -import chaiAsPromised = require('chai-as-promised'); -import ChaiBigNumber = require('chai-bignumber'); -import * as dirtyChai from 'dirty-chai'; - -export const chaiSetup = { - configure(): void { - chai.config.includeStack = true; - chai.use(ChaiBigNumber()); - chai.use(dirtyChai); - chai.use(chaiAsPromised); - }, -}; diff --git a/packages/contracts/test/utils/combinatorial_utils.ts b/packages/contracts/test/utils/combinatorial_utils.ts deleted file mode 100644 index bb1b55b4d..000000000 --- a/packages/contracts/test/utils/combinatorial_utils.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as combinatorics from 'js-combinatorics'; - -import { testWithReferenceFuncAsync } from './test_with_reference'; - -// A set of values corresponding to the uint256 type in Solidity. This set -// contains some notable edge cases, including some values which will overflow -// the uint256 type when used in different mathematical operations. -export const uint256Values = [ - new BigNumber(0), - new BigNumber(1), - new BigNumber(2), - // Non-trivial big number. - new BigNumber(2).pow(64), - // Max that does not overflow when squared. - new BigNumber(2).pow(128).minus(1), - // Min that does overflow when squared. - new BigNumber(2).pow(128), - // Max that does not overflow when doubled. - new BigNumber(2).pow(255).minus(1), - // Min that does overflow when doubled. - new BigNumber(2).pow(255), - // Max that does not overflow. - new BigNumber(2).pow(256).minus(1), -]; - -// A set of values corresponding to the bytes32 type in Solidity. -export const bytes32Values = [ - // Min - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000001', - '0x0000000000000000000000000000000000000000000000000000000000000002', - // Non-trivial big number. - '0x000000000000f000000000000000000000000000000000000000000000000000', - // Max - '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', -]; - -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, R>( - name: string, - referenceFunc: (p0: P0, p1: P1) => Promise<R>, - testFunc: (p0: P0, p1: P1) => Promise<R>, - allValues: [P0[], P1[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - allValues: [P0[], P1[], P2[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - allValues: [P0[], P1[], P2[], P3[]], -): Promise<void>; -export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>( - name: string, - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - allValues: [P0[], P1[], P2[], P3[], P4[]], -): Promise<void>; - -/** - * Uses combinatorics to test the behavior of a test function by comparing it to - * the expected behavior (defined by a reference function) for a large number of - * possible input values. - * - * First generates test cases by taking the cartesian product of the given - * values. Each test case is a set of N values corresponding to the N arguments - * for the test func and the reference func. For each test case, first the - * reference function will be called to obtain an "expected result", or if the - * reference function throws/rejects, an "expected error". Next, the test - * function will be called to obtain an "actual result", or if the test function - * throws/rejects, an "actual error". Each test case passes if at least one of - * the following conditions is met: - * - * 1) Neither the reference function or the test function throw and the - * "expected result" equals the "actual result". - * - * 2) Both the reference function and the test function throw and the "actual - * error" message *contains* the "expected error" message. - * - * The first test case which does not meet one of these conditions will cause - * the entire test to fail and this function will throw/reject. - * - * @param referenceFuncAsync a reference function implemented in pure - * JavaScript/TypeScript which accepts N arguments and returns the "expected - * result" or "expected error" for a given test case. - * @param testFuncAsync a test function which, e.g., makes a call or sends a - * transaction to a contract. It accepts the same N arguments returns the - * "actual result" or "actual error" for a given test case. - * @param values an array of N arrays. Each inner array is a set of possible - * values which are passed into both the reference function and the test - * function. - * @return A Promise that resolves if the test passes and rejects if the test - * fails, according to the rules described above. - */ -export async function testCombinatoriallyWithReferenceFuncAsync( - name: string, - referenceFuncAsync: (...args: any[]) => Promise<any>, - testFuncAsync: (...args: any[]) => Promise<any>, - allValues: any[], -): Promise<void> { - const testCases = combinatorics.cartesianProduct(...allValues); - let counter = 0; - testCases.forEach(async testCase => { - counter += 1; - it(`${name} ${counter}/${testCases.length}`, async () => { - await testWithReferenceFuncAsync(referenceFuncAsync, testFuncAsync, testCase as any); - }); - }); -} diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts deleted file mode 100644 index d2c3ab512..000000000 --- a/packages/contracts/test/utils/constants.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -const TESTRPC_PRIVATE_KEYS_STRINGS = [ - '0xf2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e0164837257d', - '0x5d862464fe9303452126c8bc94274b8c5f9874cbd219789b3eb2128075a76f72', - '0xdf02719c4df8b9b8ac7f551fcb5d9ef48fa27eef7a66453879f4d8fdc6e78fb1', - '0xff12e391b79415e941a94de3bf3a9aee577aed0731e297d5cfa0b8a1e02fa1d0', - '0x752dd9cf65e68cfaba7d60225cbdbc1f4729dd5e5507def72815ed0d8abc6249', - '0xefb595a0178eb79a8df953f87c5148402a224cdf725e88c0146727c6aceadccd', - '0x83c6d2cc5ddcf9711a6d59b417dc20eb48afd58d45290099e5987e3d768f328f', - '0xbb2d3f7c9583780a7d3904a2f55d792707c345f21de1bacb2d389934d82796b2', - '0xb2fd4d29c1390b71b8795ae81196bfd60293adf99f9d32a0aff06288fcdac55f', - '0x23cb7121166b9a2f93ae0b7c05bde02eae50d64449b2cbb42bc84e9d38d6cc89', -]; - -export const constants = { - BASE_16: 16, - INVALID_OPCODE: 'invalid opcode', - 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 - // ensure we always use the minimum interval. - AWAIT_TRANSACTION_MINED_MS: 0, - MAX_ETHERTOKEN_WITHDRAW_GAS: 43000, - MAX_EXECUTE_TRANSACTION_GAS: 1000000, - MAX_TOKEN_TRANSFERFROM_GAS: 80000, - MAX_TOKEN_APPROVE_GAS: 60000, - MAX_TRANSFER_FROM_GAS: 150000, - DUMMY_TOKEN_NAME: '', - DUMMY_TOKEN_SYMBOL: '', - DUMMY_TOKEN_DECIMALS: new BigNumber(18), - DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(0), - NULL_BYTES: '0x', - NUM_DUMMY_ERC20_TO_DEPLOY: 3, - NUM_DUMMY_ERC721_TO_DEPLOY: 2, - NUM_ERC721_TOKENS_TO_MINT: 2, - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), - TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)), - INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), - INITIAL_ERC20_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), - STATIC_ORDER_PARAMS: { - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - }, - WORD_LENGTH: 32, - ZERO_AMOUNT: new BigNumber(0), - PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18), - FUNCTIONS_WITH_MUTEX: [ - 'FILL_ORDER', - 'FILL_OR_KILL_ORDER', - 'BATCH_FILL_ORDERS', - 'BATCH_FILL_OR_KILL_ORDERS', - 'MARKET_BUY_ORDERS', - 'MARKET_SELL_ORDERS', - 'MATCH_ORDERS', - 'CANCEL_ORDER', - 'BATCH_CANCEL_ORDERS', - 'CANCEL_ORDERS_UP_TO', - 'SET_SIGNATURE_VALIDATOR_APPROVAL', - ], -}; diff --git a/packages/contracts/test/utils/coverage.ts b/packages/contracts/test/utils/coverage.ts deleted file mode 100644 index 5becfa1b6..000000000 --- a/packages/contracts/test/utils/coverage.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let coverageSubprovider: CoverageSubprovider; - -export const coverage = { - getCoverageSubproviderSingleton(): CoverageSubprovider { - if (_.isUndefined(coverageSubprovider)) { - coverageSubprovider = coverage._getCoverageSubprovider(); - } - return coverageSubprovider; - }, - _getCoverageSubprovider(): CoverageSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/packages/contracts/test/utils/erc20_wrapper.ts b/packages/contracts/test/utils/erc20_wrapper.ts deleted file mode 100644 index c281a2abf..000000000 --- a/packages/contracts/test/utils/erc20_wrapper.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { assetDataUtils } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; -import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy'; -import { artifacts } from '../../src/artifacts'; - -import { constants } from './constants'; -import { ERC20BalancesByOwner } from './types'; -import { txDefaults } from './web3_wrapper'; - -export class ERC20Wrapper { - private readonly _tokenOwnerAddresses: string[]; - private readonly _contractOwnerAddress: string; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _provider: Provider; - private readonly _dummyTokenContracts: DummyERC20TokenContract[]; - private _proxyContract?: ERC20ProxyContract; - private _proxyIdIfExists?: string; - /** - * Instanitates an ERC20Wrapper - * @param provider Web3 provider to use for all JSON RPC requests - * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens - * @param contractOwnerAddress Desired owner of the contract - * Instance of ERC20Wrapper - */ - constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { - this._dummyTokenContracts = []; - this._web3Wrapper = new Web3Wrapper(provider); - this._provider = provider; - this._tokenOwnerAddresses = tokenOwnerAddresses; - this._contractOwnerAddress = contractOwnerAddress; - } - public async deployDummyTokensAsync( - numberToDeploy: number, - decimals: BigNumber, - ): Promise<DummyERC20TokenContract[]> { - for (let i = 0; i < numberToDeploy; i++) { - this._dummyTokenContracts.push( - await DummyERC20TokenContract.deployFrom0xArtifactAsync( - artifacts.DummyERC20Token, - this._provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - decimals, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ), - ); - } - return this._dummyTokenContracts; - } - public async deployProxyAsync(): Promise<ERC20ProxyContract> { - this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC20Proxy, - this._provider, - txDefaults, - ); - this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); - return this._proxyContract; - } - public getProxyId(): string { - this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as string; - } - public async setBalancesAndAllowancesAsync(): Promise<void> { - this._validateDummyTokenContractsExistOrThrow(); - this._validateProxyContractExistsOrThrow(); - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - await this._web3Wrapper.awaitTransactionSuccessAsync( - await dummyTokenContract.setBalance.sendTransactionAsync( - tokenOwnerAddress, - constants.INITIAL_ERC20_BALANCE, - { from: this._contractOwnerAddress }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await dummyTokenContract.approve.sendTransactionAsync( - (this._proxyContract as ERC20ProxyContract).address, - constants.INITIAL_ERC20_ALLOWANCE, - { from: tokenOwnerAddress }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } - } - } - public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { - const tokenContract = this._getTokenContractFromAssetData(assetData); - const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress)); - return balance; - } - public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { - const tokenContract = this._getTokenContractFromAssetData(assetData); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, { - from: this._contractOwnerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } - public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { - 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<void> { - const tokenContract = this._getTokenContractFromAssetData(assetData); - const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; - await this._web3Wrapper.awaitTransactionSuccessAsync( - await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, { - from: userAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } - public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { - this._validateDummyTokenContractsExistOrThrow(); - const balancesByOwner: ERC20BalancesByOwner = {}; - const balances: BigNumber[] = []; - const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress)); - balanceInfo.push({ - tokenOwnerAddress, - tokenAddress: dummyTokenContract.address, - }); - } - } - _.forEach(balances, (balance, balanceIndex) => { - const tokenAddress = balanceInfo[balanceIndex].tokenAddress; - const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress; - if (_.isUndefined(balancesByOwner[tokenOwnerAddress])) { - balancesByOwner[tokenOwnerAddress] = {}; - } - const wrappedBalance = new BigNumber(balance); - balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance; - }); - return balancesByOwner; - } - public addDummyTokenContract(dummy: DummyERC20TokenContract): void { - if (!_.isUndefined(this._dummyTokenContracts)) { - this._dummyTokenContracts.push(dummy); - } - } - public addTokenOwnerAddress(address: string): void { - this._tokenOwnerAddresses.push(address); - } - public getTokenOwnerAddresses(): string[] { - return this._tokenOwnerAddresses; - } - public getTokenAddresses(): string[] { - const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); - return tokenAddresses; - } - private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract { - const erc20ProxyData = assetDataUtils.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"'); - } - } - private _validateProxyContractExistsOrThrow(): void { - if (_.isUndefined(this._proxyContract)) { - throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"'); - } - } -} diff --git a/packages/contracts/test/utils/erc721_wrapper.ts b/packages/contracts/test/utils/erc721_wrapper.ts deleted file mode 100644 index e9da553d0..000000000 --- a/packages/contracts/test/utils/erc721_wrapper.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token'; -import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy'; -import { artifacts } from '../../src/artifacts'; - -import { constants } from './constants'; -import { ERC721TokenIdsByOwner } from './types'; -import { txDefaults } from './web3_wrapper'; - -export class ERC721Wrapper { - private readonly _tokenOwnerAddresses: string[]; - private readonly _contractOwnerAddress: string; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _provider: Provider; - private readonly _dummyTokenContracts: DummyERC721TokenContract[]; - private _proxyContract?: ERC721ProxyContract; - private _proxyIdIfExists?: string; - private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; - constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { - this._web3Wrapper = new Web3Wrapper(provider); - this._provider = provider; - this._dummyTokenContracts = []; - this._tokenOwnerAddresses = tokenOwnerAddresses; - this._contractOwnerAddress = contractOwnerAddress; - } - public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> { - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) { - this._dummyTokenContracts.push( - await DummyERC721TokenContract.deployFrom0xArtifactAsync( - artifacts.DummyERC721Token, - this._provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ), - ); - } - return this._dummyTokenContracts; - } - public async deployProxyAsync(): Promise<ERC721ProxyContract> { - this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC721Proxy, - this._provider, - txDefaults, - ); - this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); - return this._proxyContract; - } - public getProxyId(): string { - this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as string; - } - public async setBalancesAndAllowancesAsync(): Promise<void> { - this._validateDummyTokenContractsExistOrThrow(); - this._validateProxyContractExistsOrThrow(); - this._initialTokenIdsByOwner = {}; - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) { - const tokenId = generatePseudoRandomSalt(); - await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); - if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) { - this._initialTokenIdsByOwner[tokenOwnerAddress] = { - [dummyTokenContract.address]: [], - }; - } - if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { - this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; - } - this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); - - await this.approveProxyAsync(dummyTokenContract.address, tokenId); - } - } - } - } - public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const owner = await tokenContract.ownerOf.callAsync(tokenId); - const doesExist = owner !== constants.NULL_ADDRESS; - return doesExist; - } - public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> { - const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; - await this.approveAsync(proxyAddress, tokenAddress, tokenId); - } - public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> { - 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<void> { - 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<void> { - 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<void> { - 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<void> { - 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<string> { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const owner = await tokenContract.ownerOf.callAsync(tokenId); - return owner; - } - public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { - 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): Promise<boolean> { - this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const operator = (this._proxyContract as ERC721ProxyContract).address; - const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); - return didApproveAll; - } - public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { - 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<ERC721TokenIdsByOwner> { - this._validateDummyTokenContractsExistOrThrow(); - this._validateBalancesAndAllowancesSetOrThrow(); - const tokenIdsByOwner: ERC721TokenIdsByOwner = {}; - const tokenOwnerAddresses: string[] = []; - const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = []; - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][ - dummyTokenContract.address - ]; - for (const tokenId of initialTokenOwnerIds) { - tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId)); - tokenInfo.push({ - tokenId, - tokenAddress: dummyTokenContract.address, - }); - } - } - } - _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { - const tokenAddress = tokenInfo[ownerIndex].tokenAddress; - const tokenId = tokenInfo[ownerIndex].tokenId; - if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress])) { - tokenIdsByOwner[tokenOwnerAddress] = { - [tokenAddress]: [], - }; - } - if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress][tokenAddress])) { - tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = []; - } - tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId); - }); - return tokenIdsByOwner; - } - public getTokenOwnerAddresses(): string[] { - return this._tokenOwnerAddresses; - } - public getTokenAddresses(): string[] { - 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"'); - } - } - private _validateProxyContractExistsOrThrow(): void { - if (_.isUndefined(this._proxyContract)) { - throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"'); - } - } - private _validateBalancesAndAllowancesSetOrThrow(): void { - if (_.keys(this._initialTokenIdsByOwner).length === 0) { - throw new Error( - 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', - ); - } - } -} diff --git a/packages/contracts/test/utils/exchange_wrapper.ts b/packages/contracts/test/utils/exchange_wrapper.ts deleted file mode 100644 index c28989d3f..000000000 --- a/packages/contracts/test/utils/exchange_wrapper.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { ExchangeContract } from '../../generated-wrappers/exchange'; - -import { formatters } from './formatters'; -import { LogDecoder } from './log_decoder'; -import { orderUtils } from './order_utils'; -import { FillResults, OrderInfo, SignedTransaction } from './types'; - -export class ExchangeWrapper { - private readonly _exchange: ExchangeContract; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _logDecoder: LogDecoder; - constructor(exchangeContract: ExchangeContract, provider: Provider) { - this._exchange = exchangeContract; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); - } - public async fillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrder.sendTransactionAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - { from }, - ); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return txReceipt; - } - public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> { - const params = orderUtils.createCancel(signedOrder); - const txHash = await this._exchange.cancelOrder.sendTransactionAsync(params.order, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async fillOrKillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async fillOrderNoThrowAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - { from, gas: opts.gas }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async batchFillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[] } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const txHash = await this._exchange.batchFillOrders.sendTransactionAsync( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async batchFillOrKillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[] } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const txHash = await this._exchange.batchFillOrKillOrders.sendTransactionAsync( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async batchFillOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const txHash = await this._exchange.batchFillOrdersNoThrow.sendTransactionAsync( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - { from, gas: opts.gas }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketSellOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber }, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); - const txHash = await this._exchange.marketSellOrders.sendTransactionAsync( - params.orders, - params.takerAssetFillAmount, - params.signatures, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketSellOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber; gas?: number }, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); - const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync( - params.orders, - params.takerAssetFillAmount, - params.signatures, - { from, gas: opts.gas }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketBuyOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber }, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); - const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync( - params.orders, - params.makerAssetFillAmount, - params.signatures, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketBuyOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber; gas?: number }, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); - const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync( - params.orders, - params.makerAssetFillAmount, - params.signatures, - { from, gas: opts.gas }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async batchCancelOrdersAsync( - orders: SignedOrder[], - from: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = formatters.createBatchCancel(orders); - const txHash = await this._exchange.batchCancelOrders.sendTransactionAsync(params.orders, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._exchange.cancelOrdersUpTo.sendTransactionAsync(salt, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async registerAssetProxyAsync( - assetProxyAddress: string, - from: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._exchange.registerAssetProxy.sendTransactionAsync(assetProxyAddress, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async executeTransactionAsync( - signedTx: SignedTransaction, - from: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._exchange.executeTransaction.sendTransactionAsync( - signedTx.salt, - signedTx.signerAddress, - signedTx.data, - signedTx.signature, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> { - const filledAmount = await this._exchange.filled.callAsync(orderHashHex); - return filledAmount; - } - public async isCancelledAsync(orderHashHex: string): Promise<boolean> { - const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex); - return isCancelled; - } - public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> { - const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress); - return orderEpoch; - } - public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> { - const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo; - return orderInfo; - } - public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> { - const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[]; - return ordersInfo; - } - public async matchOrdersAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const txHash = await this._exchange.matchOrders.sendTransactionAsync( - params.left, - params.right, - params.leftSignature, - params.rightSignature, - { from }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async getFillOrderResultsAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise<FillResults> { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const fillResults = await this._exchange.fillOrder.callAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - { from }, - ); - return fillResults; - } - public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this._exchange.fillOrder.getABIEncodedTransactionData( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - return data; - } - public getExchangeAddress(): string { - return this._exchange.address; - } -} diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts deleted file mode 100644 index 8046771f9..000000000 --- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts +++ /dev/null @@ -1,924 +0,0 @@ -import { - assetDataUtils, - BalanceAndProxyAllowanceLazyStore, - ExchangeTransferSimulator, - orderHashUtils, - OrderStateUtils, - OrderValidationUtils, -} from '@0x/order-utils'; -import { AssetProxyId, RevertReason, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber, errorUtils, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { LogWithDecodedArgs, Provider, TxData } from 'ethereum-types'; -import * as _ from 'lodash'; -import 'make-promises-safe'; - -import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange'; -import { TestLibsContract } from '../../generated-wrappers/test_libs'; -import { artifacts } from '../../src/artifacts'; - -import { expectTransactionFailedAsync } from './assertions'; -import { AssetWrapper } from './asset_wrapper'; -import { chaiSetup } from './chai_setup'; -import { constants } from './constants'; -import { ERC20Wrapper } from './erc20_wrapper'; -import { ERC721Wrapper } from './erc721_wrapper'; -import { ExchangeWrapper } from './exchange_wrapper'; -import { OrderFactoryFromScenario } from './order_factory_from_scenario'; -import { orderUtils } from './order_utils'; -import { signingUtils } from './signing_utils'; -import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher'; -import { SimpleOrderFilledCancelledFetcher } from './simple_order_filled_cancelled_fetcher'; -import { - AllowanceAmountScenario, - AssetDataScenario, - BalanceAmountScenario, - ExpirationTimeSecondsScenario, - FeeRecipientAddressScenario, - FillScenario, - OrderAssetAmountScenario, - TakerAssetFillAmountScenario, - TakerScenario, - TraderStateScenario, -} from './types'; - -chaiSetup.configure(); -const expect = chai.expect; - -/** - * Instantiates a new instance of FillOrderCombinatorialUtils. Since this method has some - * required async setup, a factory method is required. - * @param web3Wrapper Web3Wrapper instance - * @param txDefaults Default Ethereum tx options - * @return FillOrderCombinatorialUtils instance - */ -export async function fillOrderCombinatorialUtilsFactoryAsync( - web3Wrapper: Web3Wrapper, - txDefaults: Partial<TxData>, -): Promise<FillOrderCombinatorialUtils> { - 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)]; - - 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 = assetDataUtils.encodeERC20AssetData(zrxToken.address); - - const erc20FiveDecimalTokenCount = 2; - const fiveDecimals = new BigNumber(5); - const [erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync( - erc20FiveDecimalTokenCount, - fiveDecimals, - ); - const zeroDecimals = new BigNumber(0); - const erc20ZeroDecimalTokenCount = 2; - const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync( - erc20ZeroDecimalTokenCount, - zeroDecimals, - ); - 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(erc20Proxy.address, ownerAddress); - await exchangeWrapper.registerAssetProxyAsync(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 OrderFactoryFromScenario( - userAddresses, - zrxToken.address, - [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address], - [erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address], - [erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address], - erc721Token, - erc721Balances, - exchangeContract.address, - ); - - const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); - - const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( - orderFactory, - ownerAddress, - makerAddress, - makerPrivateKey, - takerAddress, - zrxAssetData, - exchangeWrapper, - assetWrapper, - testLibsContract, - ); - return fillOrderCombinatorialUtils; -} - -export class FillOrderCombinatorialUtils { - public orderFactory: OrderFactoryFromScenario; - public ownerAddress: string; - public makerAddress: string; - public makerPrivateKey: Buffer; - public takerAddress: string; - public zrxAssetData: string; - public exchangeWrapper: ExchangeWrapper; - public assetWrapper: AssetWrapper; - public testLibsContract: TestLibsContract; - public static generateFillOrderCombinations(): FillScenario[] { - const takerScenarios = [ - TakerScenario.Unspecified, - // TakerScenario.CorrectlySpecified, - // TakerScenario.IncorrectlySpecified, - ]; - const feeRecipientScenarios = [ - FeeRecipientAddressScenario.EthUserAddress, - // FeeRecipientAddressScenario.BurnAddress, - ]; - const makerAssetAmountScenario = [ - OrderAssetAmountScenario.Large, - // OrderAssetAmountScenario.Zero, - // OrderAssetAmountScenario.Small, - ]; - const takerAssetAmountScenario = [ - OrderAssetAmountScenario.Large, - // OrderAssetAmountScenario.Zero, - // OrderAssetAmountScenario.Small, - ]; - const makerFeeScenario = [ - OrderAssetAmountScenario.Large, - // OrderAssetAmountScenario.Small, - // OrderAssetAmountScenario.Zero, - ]; - const takerFeeScenario = [ - OrderAssetAmountScenario.Large, - // OrderAssetAmountScenario.Small, - // OrderAssetAmountScenario.Zero, - ]; - const expirationTimeSecondsScenario = [ - ExpirationTimeSecondsScenario.InFuture, - ExpirationTimeSecondsScenario.InPast, - ]; - const makerAssetDataScenario = [ - AssetDataScenario.ERC20FiveDecimals, - AssetDataScenario.ERC20NonZRXEighteenDecimals, - AssetDataScenario.ERC721, - AssetDataScenario.ZRXFeeToken, - ]; - const takerAssetDataScenario = [ - AssetDataScenario.ERC20FiveDecimals, - AssetDataScenario.ERC20NonZRXEighteenDecimals, - AssetDataScenario.ERC721, - AssetDataScenario.ZRXFeeToken, - ]; - const takerAssetFillAmountScenario = [ - TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount, - // TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount, - // TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount, - ]; - const makerAssetBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - ]; - const makerAssetAllowanceScenario = [ - AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - // AllowanceAmountScenario.Unlimited, - ]; - const makerZRXBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - ]; - const makerZRXAllowanceScenario = [ - AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - // AllowanceAmountScenario.Unlimited, - ]; - const takerAssetBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - ]; - const takerAssetAllowanceScenario = [ - AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - // AllowanceAmountScenario.Unlimited, - ]; - const takerZRXBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - ]; - const takerZRXAllowanceScenario = [ - AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - // AllowanceAmountScenario.Unlimited, - ]; - const fillScenarioArrays = FillOrderCombinatorialUtils._getAllCombinations([ - takerScenarios, - feeRecipientScenarios, - makerAssetAmountScenario, - takerAssetAmountScenario, - makerFeeScenario, - takerFeeScenario, - expirationTimeSecondsScenario, - makerAssetDataScenario, - takerAssetDataScenario, - takerAssetFillAmountScenario, - makerAssetBalanceScenario, - makerAssetAllowanceScenario, - makerZRXBalanceScenario, - makerZRXAllowanceScenario, - takerAssetBalanceScenario, - takerAssetAllowanceScenario, - takerZRXBalanceScenario, - takerZRXAllowanceScenario, - ]); - - const fillScenarios = _.map(fillScenarioArrays, fillScenarioArray => { - // tslint:disable:custom-no-magic-numbers - 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, - makerStateScenario: { - traderAssetBalance: fillScenarioArray[10] as BalanceAmountScenario, - traderAssetAllowance: fillScenarioArray[11] as AllowanceAmountScenario, - zrxFeeBalance: fillScenarioArray[12] as BalanceAmountScenario, - zrxFeeAllowance: fillScenarioArray[13] as AllowanceAmountScenario, - }, - takerStateScenario: { - traderAssetBalance: fillScenarioArray[14] as BalanceAmountScenario, - traderAssetAllowance: fillScenarioArray[15] as AllowanceAmountScenario, - zrxFeeBalance: fillScenarioArray[16] as BalanceAmountScenario, - zrxFeeAllowance: fillScenarioArray[17] as AllowanceAmountScenario, - }, - }; - // tslint:enable:custom-no-magic-numbers - return fillScenario; - }); - - return fillScenarios; - } - /** - * 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 remainingValues = _.map(arrays[0], val => { - return [val]; - }); - return remainingValues; - } else { - const result = []; - const restOfArrays = arrays.slice(1); - const allCombinationsOfRemaining = FillOrderCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array - // tslint:disable:prefer-for-of - for (let i = 0; i < allCombinationsOfRemaining.length; i++) { - for (let j = 0; j < arrays[0].length; j++) { - result.push([arrays[0][j], ...allCombinationsOfRemaining[i]]); - } - } - // tslint:enable:prefer-for-of - return result; - } - } - constructor( - orderFactory: OrderFactoryFromScenario, - ownerAddress: string, - makerAddress: string, - makerPrivateKey: Buffer, - takerAddress: string, - zrxAssetData: string, - exchangeWrapper: ExchangeWrapper, - assetWrapper: AssetWrapper, - testLibsContract: TestLibsContract, - ) { - this.orderFactory = orderFactory; - this.ownerAddress = ownerAddress; - this.makerAddress = makerAddress; - this.makerPrivateKey = makerPrivateKey; - this.takerAddress = takerAddress; - this.zrxAssetData = zrxAssetData; - this.exchangeWrapper = exchangeWrapper; - this.assetWrapper = assetWrapper; - this.testLibsContract = testLibsContract; - } - public async testFillOrderScenarioAsync( - provider: Provider, - fillScenario: FillScenario, - isVerbose: boolean = false, - ): Promise<void> { - // 1. Generate order - const order = this.orderFactory.generateOrder(fillScenario.orderScenario); - - // 2. Sign order - const orderHashBuff = orderHashUtils.getOrderHashBuffer(order); - const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign); - const signedOrder = { - ...order, - signature: `0x${signature.toString('hex')}`, - }; - - const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper); - const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher( - this.exchangeWrapper, - this.zrxAssetData, - ); - - // 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, - ); - - // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected? - const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher, provider); - const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); - const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); - - let fillRevertReasonIfExists; - try { - await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTransferSimulator, - provider, - signedOrder, - takerAssetFillAmount, - this.takerAddress, - this.zrxAssetData, - ); - if (isVerbose) { - logUtils.log(`Expecting fillOrder to succeed.`); - } - } catch (err) { - fillRevertReasonIfExists = err.message; - if (isVerbose) { - logUtils.log(`Expecting fillOrder to fail with:`); - logUtils.log(err); - } - } - - // 6. Fill the order - await this._fillOrderAndAssertOutcomeAsync( - signedOrder, - takerAssetFillAmount, - lazyStore, - fillRevertReasonIfExists, - ); - - await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount); - } - private async _fillOrderAndAssertOutcomeAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - lazyStore: BalanceAndProxyAllowanceLazyStore, - fillRevertReasonIfExists: RevertReason | undefined, - ): Promise<void> { - if (!_.isUndefined(fillRevertReasonIfExists)) { - return expectTransactionFailedAsync( - this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), - fillRevertReasonIfExists, - ); - } - - 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.getPartialAmountFloor( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - const expMakerFeePaid = orderUtils.getPartialAmountFloor( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); - const expTakerFeePaid = orderUtils.getPartialAmountFloor( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); - const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, { - takerAssetFillAmount, - }); - expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal( - expFilledTakerAmount, - 'takerAssetFilledAmount', - ); - expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal( - expFilledMakerAmount, - 'makerAssetFilledAmount', - ); - expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid'); - expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid'); - - // - 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'); - - const exchangeLogs = _.filter( - txReceipt.logs, - txLog => txLog.address === this.exchangeWrapper.getExchangeAddress(), - ); - expect(exchangeLogs.length).to.be.equal(1, 'logs length'); - // tslint:disable-next-line:no-unnecessary-type-assertion - const log = txReceipt.logs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>; - 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', - ); - expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); - 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 _abiEncodeFillOrderAndAssertOutcomeAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - ): Promise<void> { - const params = orderUtils.createFill(signedOrder, takerAssetFillAmount); - const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount }); - const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData'); - } - private async _getTakerAssetFillAmountAsync( - signedOrder: SignedOrder, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario, - balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, - orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher, - ): Promise<BigNumber> { - 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 = assetDataUtils.decodeAssetProxyId(signedOrder.takerAssetData); - const makerAssetProxyId = assetDataUtils.decodeAssetProxyId(signedOrder.makerAssetData); - const isEitherAssetERC721 = - 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.', - ); - } - takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor(); - break; - - default: - throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario); - } - - return takerAssetFillAmount; - } - private async _modifyTraderStateAsync( - makerStateScenario: TraderStateScenario, - takerStateScenario: TraderStateScenario, - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - ): Promise<void> { - const makerAssetFillAmount = orderUtils.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - switch (makerStateScenario.traderAssetBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.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 BalanceAmountScenario.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.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); - switch (makerStateScenario.zrxFeeBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.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 BalanceAmountScenario.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 AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - const tooLowAllowance = makerAssetFillAmount.minus(1); - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - signedOrder.makerAssetData, - tooLowAllowance, - ); - break; - - case AllowanceAmountScenario.Exact: - const exactAllowance = makerAssetFillAmount; - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - signedOrder.makerAssetData, - exactAllowance, - ); - 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', - makerStateScenario.traderAssetAllowance, - ); - } - - switch (makerStateScenario.zrxFeeAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - const tooLowAllowance = makerFee.minus(1); - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - this.zrxAssetData, - tooLowAllowance, - ); - break; - - case AllowanceAmountScenario.Exact: - const exactAllowance = makerFee; - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - this.zrxAssetData, - exactAllowance, - ); - 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', - makerStateScenario.zrxFeeAllowance, - ); - } - - switch (takerStateScenario.traderAssetBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.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 BalanceAmountScenario.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.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); - switch (takerStateScenario.zrxFeeBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.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 BalanceAmountScenario.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 AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - const tooLowAllowance = takerAssetFillAmount.minus(1); - await this.assetWrapper.setProxyAllowanceAsync( - this.takerAddress, - signedOrder.takerAssetData, - tooLowAllowance, - ); - break; - - case AllowanceAmountScenario.Exact: - const exactAllowance = takerAssetFillAmount; - await this.assetWrapper.setProxyAllowanceAsync( - this.takerAddress, - signedOrder.takerAssetData, - exactAllowance, - ); - 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', - takerStateScenario.traderAssetAllowance, - ); - } - - switch (takerStateScenario.zrxFeeAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - const tooLowAllowance = takerFee.minus(1); - await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, tooLowAllowance); - break; - - case AllowanceAmountScenario.Exact: - const exactAllowance = takerFee; - await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, exactAllowance); - break; - - case AllowanceAmountScenario.Unlimited: - await this.assetWrapper.setProxyAllowanceAsync( - this.takerAddress, - this.zrxAssetData, - constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - break; - - default: - throw errorUtils.spawnSwitchErr( - 'takerStateScenario.zrxFeeAllowance', - takerStateScenario.zrxFeeAllowance, - ); - } - } -} // tslint:disable:max-file-line-count diff --git a/packages/contracts/test/utils/formatters.ts b/packages/contracts/test/utils/formatters.ts deleted file mode 100644 index 813eb45db..000000000 --- a/packages/contracts/test/utils/formatters.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { orderUtils } from './order_utils'; -import { BatchCancelOrders, BatchFillOrders, MarketBuyOrders, MarketSellOrders } from './types'; - -export const formatters = { - createBatchFill(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[] = []): BatchFillOrders { - const batchFill: BatchFillOrders = { - orders: [], - signatures: [], - takerAssetFillAmounts, - }; - _.forEach(signedOrders, signedOrder => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - batchFill.orders.push(orderWithoutExchangeAddress); - batchFill.signatures.push(signedOrder.signature); - if (takerAssetFillAmounts.length < signedOrders.length) { - batchFill.takerAssetFillAmounts.push(signedOrder.takerAssetAmount); - } - }); - return batchFill; - }, - createMarketSellOrders(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): MarketSellOrders { - const marketSellOrders: MarketSellOrders = { - orders: [], - signatures: [], - takerAssetFillAmount, - }; - _.forEach(signedOrders, (signedOrder, i) => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - if (i !== 0) { - orderWithoutExchangeAddress.takerAssetData = constants.NULL_BYTES; - } - marketSellOrders.orders.push(orderWithoutExchangeAddress); - marketSellOrders.signatures.push(signedOrder.signature); - }); - return marketSellOrders; - }, - createMarketBuyOrders(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): MarketBuyOrders { - const marketBuyOrders: MarketBuyOrders = { - orders: [], - signatures: [], - makerAssetFillAmount, - }; - _.forEach(signedOrders, (signedOrder, i) => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - if (i !== 0) { - orderWithoutExchangeAddress.makerAssetData = constants.NULL_BYTES; - } - marketBuyOrders.orders.push(orderWithoutExchangeAddress); - marketBuyOrders.signatures.push(signedOrder.signature); - }); - return marketBuyOrders; - }, - createBatchCancel(signedOrders: SignedOrder[]): BatchCancelOrders { - const batchCancel: BatchCancelOrders = { - orders: [], - }; - _.forEach(signedOrders, signedOrder => { - const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); - batchCancel.orders.push(orderWithoutExchangeAddress); - }); - return batchCancel; - }, -}; diff --git a/packages/contracts/test/utils/forwarder_wrapper.ts b/packages/contracts/test/utils/forwarder_wrapper.ts deleted file mode 100644 index a0bfcfe1d..000000000 --- a/packages/contracts/test/utils/forwarder_wrapper.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ForwarderContract } from '../../generated-wrappers/forwarder'; - -import { constants } from './constants'; -import { formatters } from './formatters'; -import { LogDecoder } from './log_decoder'; -import { MarketSellOrders } from './types'; - -export class ForwarderWrapper { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _forwarderContract: ForwarderContract; - private readonly _logDecoder: LogDecoder; - public static getPercentageOfValue(value: BigNumber, percentage: number): BigNumber { - const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100); - const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR); - return newValue; - } - public static getWethForFeeOrders(feeAmount: BigNumber, feeOrders: SignedOrder[]): BigNumber { - let wethAmount = new BigNumber(0); - let remainingFeeAmount = feeAmount; - _.forEach(feeOrders, feeOrder => { - const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee); - if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) { - wethAmount = wethAmount.plus( - feeOrder.takerAssetAmount - .times(remainingFeeAmount) - .dividedBy(feeAvailable) - .ceil(), - ); - remainingFeeAmount = new BigNumber(0); - } else if (!remainingFeeAmount.isZero()) { - wethAmount = wethAmount.plus(feeOrder.takerAssetAmount); - remainingFeeAmount = remainingFeeAmount.minus(feeAvailable); - } - }); - return wethAmount; - } - private static _createOptimizedOrders(signedOrders: SignedOrder[]): MarketSellOrders { - _.forEach(signedOrders, (signedOrder, index) => { - signedOrder.takerAssetData = constants.NULL_BYTES; - if (index > 0) { - signedOrder.makerAssetData = constants.NULL_BYTES; - } - }); - const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT); - return params; - } - private static _createOptimizedZrxOrders(signedOrders: SignedOrder[]): MarketSellOrders { - _.forEach(signedOrders, signedOrder => { - signedOrder.makerAssetData = constants.NULL_BYTES; - signedOrder.takerAssetData = constants.NULL_BYTES; - }); - const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT); - return params; - } - constructor(contractInstance: ForwarderContract, provider: Provider) { - this._forwarderContract = contractInstance; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); - } - public async marketSellOrdersWithEthAsync( - orders: SignedOrder[], - feeOrders: SignedOrder[], - txData: TxDataPayable, - opts: { feePercentage?: BigNumber; feeRecipient?: string } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = ForwarderWrapper._createOptimizedOrders(orders); - const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders); - const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage; - const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient; - const txHash = await this._forwarderContract.marketSellOrdersWithEth.sendTransactionAsync( - params.orders, - params.signatures, - feeParams.orders, - feeParams.signatures, - feePercentage, - feeRecipient, - txData, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketBuyOrdersWithEthAsync( - orders: SignedOrder[], - feeOrders: SignedOrder[], - makerAssetFillAmount: BigNumber, - txData: TxDataPayable, - opts: { feePercentage?: BigNumber; feeRecipient?: string } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const params = ForwarderWrapper._createOptimizedOrders(orders); - const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders); - const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage; - const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient; - const txHash = await this._forwarderContract.marketBuyOrdersWithEth.sendTransactionAsync( - params.orders, - makerAssetFillAmount, - params.signatures, - feeParams.orders, - feeParams.signatures, - feePercentage, - feeRecipient, - txData, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async withdrawAssetAsync( - assetData: string, - amount: BigNumber, - txData: TxDataPayable, - ): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._forwarderContract.withdrawAsset.sendTransactionAsync(assetData, amount, txData); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } -} diff --git a/packages/contracts/test/utils/log_decoder.ts b/packages/contracts/test/utils/log_decoder.ts deleted file mode 100644 index 05b0a9204..000000000 --- a/packages/contracts/test/utils/log_decoder.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AbiDecoder, BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { - AbiDefinition, - ContractArtifact, - DecodedLogArgs, - LogEntry, - LogWithDecodedArgs, - RawLog, - TransactionReceiptWithDecodedLogs, -} from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from '../../src/artifacts'; - -import { constants } from './constants'; - -export class LogDecoder { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _abiDecoder: AbiDecoder; - public static wrapLogBigNumbers(log: any): any { - const argNames = _.keys(log.args); - for (const argName of argNames) { - const isWeb3BigNumber = _.startsWith(log.args[argName].constructor.toString(), 'function BigNumber('); - if (isWeb3BigNumber) { - log.args[argName] = new BigNumber(log.args[argName]); - } - } - } - constructor(web3Wrapper: Web3Wrapper) { - this._web3Wrapper = web3Wrapper; - const abiArrays: AbiDefinition[][] = []; - _.forEach(artifacts, (artifact: ContractArtifact) => { - const compilerOutput = artifact.compilerOutput; - abiArrays.push(compilerOutput.abi); - }); - this._abiDecoder = new AbiDecoder(abiArrays); - } - public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog { - const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log); - // tslint:disable-next-line:no-unnecessary-type-assertion - if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) { - throw new Error(`Unable to decode log: ${JSON.stringify(log)}`); - } - LogDecoder.wrapLogBigNumbers(logWithDecodedArgsOrLog); - return logWithDecodedArgsOrLog; - } - public async getTxWithDecodedLogsAsync(txHash: string): Promise<TransactionReceiptWithDecodedLogs> { - const tx = await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - tx.logs = _.map(tx.logs, log => this.decodeLogOrThrow(log)); - return tx; - } -} diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts deleted file mode 100644 index 6c2c84959..000000000 --- a/packages/contracts/test/utils/match_order_tester.ts +++ /dev/null @@ -1,566 +0,0 @@ -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { AssetProxyId, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import * as _ from 'lodash'; - -import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; - -import { chaiSetup } from './chai_setup'; -import { ERC20Wrapper } from './erc20_wrapper'; -import { ERC721Wrapper } from './erc721_wrapper'; -import { ExchangeWrapper } from './exchange_wrapper'; -import { - ERC20BalancesByOwner, - ERC721TokenIdsByOwner, - OrderInfo, - OrderStatus, - TransferAmountsByMatchOrders as TransferAmounts, - TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts, -} from './types'; - -chaiSetup.configure(); -const expect = chai.expect; - -export class MatchOrderTester { - private readonly _exchangeWrapper: ExchangeWrapper; - private readonly _erc20Wrapper: ERC20Wrapper; - private readonly _erc721Wrapper: ERC721Wrapper; - private readonly _feeTokenAddress: string; - /// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts. - /// Values include the amounts transferred from the left/right makers and taker, along with - /// the fees paid on each matched order. These are also the return values of MatchOrders. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders. - /// @param takerAddress Address of taker (account that called Exchange.matchOrders) - /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - private static async _assertLogsAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - transactionReceipt: TransactionReceiptWithDecodedLogs, - takerAddress: string, - expectedTransferAmounts: TransferAmounts, - ): Promise<void> { - // Should have two fill event logs -- one for each order. - const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']); - expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2); - // First log is for left fill - const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts; - expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal( - signedOrderLeft.makerAddress, - ); - expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress); - const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount); - const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount); - const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid); - const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid); - // Second log is for right fill - const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts; - expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal( - signedOrderRight.makerAddress, - ); - expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress); - const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount); - const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount); - const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid); - const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid); - // Derive amount received by taker - const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); - // Assert log values - left order - expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal( - expectedTransferAmounts.amountBoughtByLeftMaker, - ); - expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal( - expectedTransferAmounts.amountSoldByLeftMaker, - ); - expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal( - expectedTransferAmounts.feePaidByLeftMaker, - ); - expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal( - expectedTransferAmounts.feePaidByTakerLeft, - ); - // Assert log values - right order - expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal( - expectedTransferAmounts.amountBoughtByRightMaker, - ); - expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal( - expectedTransferAmounts.amountSoldByRightMaker, - ); - expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal( - expectedTransferAmounts.feePaidByRightMaker, - ); - expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal( - expectedTransferAmounts.feePaidByTakerRight, - ); - // Assert derived amount received by taker - expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal( - expectedTransferAmounts.amountReceivedByTaker, - ); - } - /// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings. - /// @param expectedERC20BalancesByOwner Expected ERC20 balances. - /// @param realERC20BalancesByOwner Real ERC20 balances. - /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. - /// @param realERC721TokenIdsByOwner Real ERC20 token owners. - private static async _assertAllKnownBalancesAsync( - expectedERC20BalancesByOwner: ERC20BalancesByOwner, - realERC20BalancesByOwner: ERC20BalancesByOwner, - expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - ): Promise<void> { - // ERC20 Balances - const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner); - expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true(); - // ERC721 Token Ids - const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => { - _.mapValues(tokenIdsByOwner, tokenIds => { - _.sortBy(tokenIds); - }); - }); - const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => { - _.mapValues(tokenIdsByOwner, tokenIds => { - _.sortBy(tokenIds); - }); - }); - const areERC721TokenIdsEqual = _.isEqual( - sortedExpectedNewERC721TokenIdsByOwner, - sortedNewERC721TokenIdsByOwner, - ); - expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true(); - } - /// @dev Constructs new MatchOrderTester. - /// @param exchangeWrapper Used to call to the Exchange. - /// @param erc20Wrapper Used to fetch ERC20 balances. - /// @param erc721Wrapper Used to fetch ERC721 token owners. - /// @param feeTokenAddress Address of ERC20 fee token. - constructor( - exchangeWrapper: ExchangeWrapper, - erc20Wrapper: ERC20Wrapper, - erc721Wrapper: ERC721Wrapper, - feeTokenAddress: string, - ) { - this._exchangeWrapper = exchangeWrapper; - this._erc20Wrapper = erc20Wrapper; - this._erc721Wrapper = erc721Wrapper; - this._feeTokenAddress = feeTokenAddress; - } - /// @dev Matches two complementary orders and asserts results. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param takerAddress Address of taker (the address who matched the two orders) - /// @param erc20BalancesByOwner Current ERC20 balances. - /// @param erc721TokenIdsByOwner Current ERC721 token owners. - /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. - /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. - /// @return New ERC20 balances & ERC721 token owners. - public async matchOrdersAndAssertEffectsAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - takerAddress: string, - erc20BalancesByOwner: ERC20BalancesByOwner, - erc721TokenIdsByOwner: ERC721TokenIdsByOwner, - expectedTransferAmounts: TransferAmounts, - initialLeftOrderFilledAmount: BigNumber = new BigNumber(0), - initialRightOrderFilledAmount: BigNumber = new BigNumber(0), - ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { - // Assert initial order states - await this._assertInitialOrderStatesAsync( - signedOrderLeft, - signedOrderRight, - initialLeftOrderFilledAmount, - initialRightOrderFilledAmount, - ); - // Match left & right orders - const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - ); - const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); - const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); - // Assert logs - await MatchOrderTester._assertLogsAsync( - signedOrderLeft, - signedOrderRight, - transactionReceipt, - takerAddress, - expectedTransferAmounts, - ); - // Assert exchange state - await this._assertExchangeStateAsync( - signedOrderLeft, - signedOrderRight, - initialLeftOrderFilledAmount, - initialRightOrderFilledAmount, - expectedTransferAmounts, - ); - // Assert balances of makers, taker, and fee recipients - await this._assertBalancesAsync( - signedOrderLeft, - signedOrderRight, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - newERC20BalancesByOwner, - newERC721TokenIdsByOwner, - expectedTransferAmounts, - takerAddress, - ); - return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; - } - /// @dev Asserts initial exchange state for the left and right orders. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders. - /// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders. - private async _assertInitialOrderStatesAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - expectedOrderFilledAmountLeft: BigNumber, - expectedOrderFilledAmountRight: BigNumber, - ): Promise<void> { - // Assert left order initial state - const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderLeft), - ); - expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( - expectedOrderFilledAmountLeft, - ); - // Assert right order initial state - const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderRight), - ); - expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal( - expectedOrderFilledAmountRight, - ); - } - /// @dev Asserts the exchange state against the expected amounts transferred by from matching orders. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. - /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. - /// @return TransferAmounts A struct containing the expected transfer amounts. - private async _assertExchangeStateAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - initialLeftOrderFilledAmount: BigNumber, - initialRightOrderFilledAmount: BigNumber, - expectedTransferAmounts: TransferAmounts, - ): Promise<void> { - // Assert state for left order: amount bought by left maker - let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderLeft), - ); - amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount); - expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal( - expectedTransferAmounts.amountBoughtByLeftMaker, - ); - // Assert state for right order: amount bought by right maker - let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderRight), - ); - amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount); - expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal( - expectedTransferAmounts.amountBoughtByRightMaker, - ); - // Assert left order status - const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount); - const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker) - ? OrderStatus.FULLY_FILLED - : OrderStatus.FILLABLE; - expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal( - leftExpectedStatus, - ); - // Assert right order status - const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount); - const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); - const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker) - ? OrderStatus.FULLY_FILLED - : OrderStatus.FILLABLE; - expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal( - rightExpectedStatus, - ); - } - /// @dev Asserts account balances after matching orders. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param initialERC20BalancesByOwner ERC20 balances prior to order matching. - /// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching. - /// @param finalERC20BalancesByOwner ERC20 balances after order matching. - /// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching. - /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - /// @param takerAddress Address of taker (account that called Exchange.matchOrders). - private async _assertBalancesAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - initialERC20BalancesByOwner: ERC20BalancesByOwner, - initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - finalERC20BalancesByOwner: ERC20BalancesByOwner, - finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - expectedTransferAmounts: TransferAmounts, - takerAddress: string, - ): Promise<void> { - let expectedERC20BalancesByOwner: ERC20BalancesByOwner; - let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; - [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( - signedOrderLeft, - signedOrderRight, - takerAddress, - initialERC20BalancesByOwner, - initialERC721TokenIdsByOwner, - expectedTransferAmounts, - ); - // Assert balances of makers, taker, and fee recipients - await this._assertMakerTakerAndFeeRecipientBalancesAsync( - signedOrderLeft, - signedOrderRight, - expectedERC20BalancesByOwner, - finalERC20BalancesByOwner, - expectedERC721TokenIdsByOwner, - finalERC721TokenIdsByOwner, - takerAddress, - ); - // Assert balances for all known accounts - await MatchOrderTester._assertAllKnownBalancesAsync( - expectedERC20BalancesByOwner, - finalERC20BalancesByOwner, - expectedERC721TokenIdsByOwner, - finalERC721TokenIdsByOwner, - ); - } - /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, - /// as a result of matching two orders. - /// @param signedOrderRight First matched order. - /// @param signedOrderRight Second matched order. - /// @param takerAddress Address of taker (the address who matched the two orders) - /// @param erc20BalancesByOwner Current ERC20 balances. - /// @param erc721TokenIdsByOwner Current ERC721 token owners. - /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - /// @return Expected ERC20 balances & ERC721 token owners after orders have been matched. - private _calculateExpectedBalances( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - takerAddress: string, - erc20BalancesByOwner: ERC20BalancesByOwner, - erc721TokenIdsByOwner: ERC721TokenIdsByOwner, - expectedTransferAmounts: TransferAmounts, - ): [ERC20BalancesByOwner, ERC721TokenIdsByOwner] { - const makerAddressLeft = signedOrderLeft.makerAddress; - const makerAddressRight = signedOrderRight.makerAddress; - const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress; - const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress; - // Operations are performed on copies of the balances - const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner); - const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner); - // Left Maker Asset (Right Taker Asset) - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { - // Decode asset data - const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = erc20AssetData.tokenAddress; - const takerAssetAddressRight = makerAssetAddressLeft; - // Left Maker - expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[ - makerAddressLeft - ][makerAssetAddressLeft].minus(expectedTransferAmounts.amountSoldByLeftMaker); - // Right Maker - expectedNewERC20BalancesByOwner[makerAddressRight][ - takerAssetAddressRight - ] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add( - expectedTransferAmounts.amountBoughtByRightMaker, - ); - // Taker - expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[ - takerAddress - ][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker); - } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) { - // Decode asset data - const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = erc721AssetData.tokenAddress; - const makerAssetIdLeft = erc721AssetData.tokenId; - const takerAssetAddressRight = makerAssetAddressLeft; - const takerAssetIdRight = makerAssetIdLeft; - // Left Maker - _.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft); - // Right Maker - expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight); - // Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset. - } - // Left Taker Asset (Right Maker Asset) - // Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset. - const takerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.takerAssetData); - if (takerAssetProxyIdLeft === AssetProxyId.ERC20) { - // Decode asset data - const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData); - const takerAssetAddressLeft = erc20AssetData.tokenAddress; - const makerAssetAddressRight = takerAssetAddressLeft; - // Left Maker - expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[ - makerAddressLeft - ][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker); - // Right Maker - expectedNewERC20BalancesByOwner[makerAddressRight][ - makerAssetAddressRight - ] = expectedNewERC20BalancesByOwner[makerAddressRight][makerAssetAddressRight].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ); - } else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) { - // Decode asset data - const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = erc721AssetData.tokenAddress; - const makerAssetIdRight = erc721AssetData.tokenId; - const takerAssetAddressLeft = makerAssetAddressRight; - const takerAssetIdLeft = makerAssetIdRight; - // Right Maker - _.remove(expectedNewERC721TokenIdsByOwner[makerAddressRight][makerAssetAddressRight], makerAssetIdRight); - // Left Maker - expectedNewERC721TokenIdsByOwner[makerAddressLeft][takerAssetAddressLeft].push(takerAssetIdLeft); - } - // Left Maker Fees - expectedNewERC20BalancesByOwner[makerAddressLeft][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[ - makerAddressLeft - ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByLeftMaker); - // Right Maker Fees - expectedNewERC20BalancesByOwner[makerAddressRight][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[ - makerAddressRight - ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByRightMaker); - // Taker Fees - expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[ - takerAddress - ][this._feeTokenAddress].minus( - expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight), - ); - // Left Fee Recipient Fees - expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][ - this._feeTokenAddress - ] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add( - expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft), - ); - // Right Fee Recipient Fees - expectedNewERC20BalancesByOwner[feeRecipientAddressRight][ - this._feeTokenAddress - ] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add( - expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight), - ); - - return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; - } - /// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching. - /// Specifically checks balances of makers, taker and fee recipients. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param expectedERC20BalancesByOwner Expected ERC20 balances. - /// @param realERC20BalancesByOwner Real ERC20 balances. - /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. - /// @param realERC721TokenIdsByOwner Real ERC20 token owners. - /// @param takerAddress Address of taker (account that called Exchange.matchOrders). - private async _assertMakerTakerAndFeeRecipientBalancesAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - expectedERC20BalancesByOwner: ERC20BalancesByOwner, - realERC20BalancesByOwner: ERC20BalancesByOwner, - expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - takerAddress: string, - ): Promise<void> { - // Individual balance comparisons - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - const makerERC20AssetDataLeft = - makerAssetProxyIdLeft === AssetProxyId.ERC20 - ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) - : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; - const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); - const makerERC20AssetDataRight = - makerAssetProxyIdRight === AssetProxyId.ERC20 - ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) - : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; - if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], - 'Checking left maker egress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], - 'Checking right maker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); - expect( - realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], - 'Checking taker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); - } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) { - expect( - realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), - 'Checking left maker egress ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), - ); - expect( - realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), - 'Checking right maker ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), - ); - expect( - realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), - 'Checking taker ingress ERC721 account holdings', - ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - if (makerAssetProxyIdRight === AssetProxyId.ERC20) { - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], - 'Checking left maker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - 'Checking right maker egress ERC20 account balance', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - ); - } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) { - expect( - realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), - 'Checking left maker ingress ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), - ); - expect( - realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - 'Checking right maker agress ERC721 account holdings', - ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); - } - // Paid fees - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], - 'Checking left maker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], - 'Checking right maker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - expect( - realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], - 'Checking taker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); - // Received fees - expect( - realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], - 'Checking left fee recipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], - ); - expect( - realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], - 'Checking right fee receipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], - ); - } -} // tslint:disable-line:max-file-line-count diff --git a/packages/contracts/test/utils/multi_sig_wrapper.ts b/packages/contracts/test/utils/multi_sig_wrapper.ts deleted file mode 100644 index 74fd3b4d6..000000000 --- a/packages/contracts/test/utils/multi_sig_wrapper.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { AssetProxyOwnerContract } from '../../generated-wrappers/asset_proxy_owner'; -import { MultiSigWalletContract } from '../../generated-wrappers/multi_sig_wallet'; - -import { LogDecoder } from './log_decoder'; - -export class MultiSigWrapper { - private readonly _multiSig: MultiSigWalletContract; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _logDecoder: LogDecoder; - constructor(multiSigContract: MultiSigWalletContract, provider: Provider) { - this._multiSig = multiSigContract; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper); - } - public async submitTransactionAsync( - destination: string, - data: string, - from: string, - opts: { value?: BigNumber } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const value = _.isUndefined(opts.value) ? new BigNumber(0) : opts.value; - const txHash = await this._multiSig.submitTransaction.sendTransactionAsync(destination, value, data, { - from, - }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async confirmTransactionAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._multiSig.confirmTransaction.sendTransactionAsync(txId, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async revokeConfirmationAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._multiSig.revokeConfirmation.sendTransactionAsync(txId, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async executeTransactionAsync( - txId: BigNumber, - from: string, - opts: { gas?: number } = {}, - ): Promise<TransactionReceiptWithDecodedLogs> { - const txHash = await this._multiSig.executeTransaction.sendTransactionAsync(txId, { - from, - gas: opts.gas, - }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async executeRemoveAuthorizedAddressAtIndexAsync( - txId: BigNumber, - from: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - // tslint:disable-next-line:no-unnecessary-type-assertion - const txHash = await (this - ._multiSig as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { - from, - }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } -} diff --git a/packages/contracts/test/utils/order_factory.ts b/packages/contracts/test/utils/order_factory.ts deleted file mode 100644 index 2449d1a8a..000000000 --- a/packages/contracts/test/utils/order_factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils'; -import { Order, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { getLatestBlockTimestampAsync } from './block_timestamp'; -import { constants } from './constants'; -import { signingUtils } from './signing_utils'; - -export class OrderFactory { - private readonly _defaultOrderParams: Partial<Order>; - private readonly _privateKey: Buffer; - constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) { - this._defaultOrderParams = defaultOrderParams; - this._privateKey = privateKey; - } - public async newSignedOrderAsync( - customOrderParams: Partial<Order> = {}, - signatureType: SignatureType = SignatureType.EthSign, - ): Promise<SignedOrder> { - const tenMinutesInSeconds = 10 * 60; - const currentBlockTimestamp = await getLatestBlockTimestampAsync(); - const order = ({ - senderAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: new BigNumber(currentBlockTimestamp).add(tenMinutesInSeconds), - salt: generatePseudoRandomSalt(), - takerAddress: constants.NULL_ADDRESS, - ...this._defaultOrderParams, - ...customOrderParams, - } as any) as Order; - const orderHashBuff = orderHashUtils.getOrderHashBuffer(order); - const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType); - const signedOrder = { - ...order, - signature: `0x${signature.toString('hex')}`, - }; - return signedOrder; - } -} diff --git a/packages/contracts/test/utils/order_factory_from_scenario.ts b/packages/contracts/test/utils/order_factory_from_scenario.ts deleted file mode 100644 index 60c8606c4..000000000 --- a/packages/contracts/test/utils/order_factory_from_scenario.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { Order } from '@0x/types'; -import { BigNumber, errorUtils } from '@0x/utils'; - -import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token'; - -import { constants } from './constants'; -import { - AssetDataScenario, - ERC721TokenIdsByOwner, - ExpirationTimeSecondsScenario, - FeeRecipientAddressScenario, - OrderAssetAmountScenario, - OrderScenario, - TakerScenario, -} from './types'; - -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 TEN_UNITS_ZERO_DECIMALS = new BigNumber(10); -const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000); -const ONE_NFT_UNIT = new BigNumber(1); - -export class OrderFactoryFromScenario { - private readonly _userAddresses: string[]; - private readonly _zrxAddress: string; - private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[]; - private readonly _erc20FiveDecimalTokenAddresses: string[]; - private readonly _erc20ZeroDecimalTokenAddresses: string[]; - private readonly _erc721Token: DummyERC721TokenContract; - private readonly _erc721Balances: ERC721TokenIdsByOwner; - private readonly _exchangeAddress: string; - constructor( - userAddresses: string[], - zrxAddress: string, - nonZrxERC20EighteenDecimalTokenAddresses: string[], - erc20FiveDecimalTokenAddresses: string[], - erc20ZeroDecimalTokenAddresses: string[], - erc721Token: DummyERC721TokenContract, - erc721Balances: ERC721TokenIdsByOwner, - exchangeAddress: string, - ) { - this._userAddresses = userAddresses; - this._zrxAddress = zrxAddress; - this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses; - this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses; - this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses; - 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 = assetDataUtils.encodeERC20AssetData(this._zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - makerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC721: - makerAssetData = assetDataUtils.encodeERC721AssetData( - this._erc721Token.address, - erc721MakerAssetIds[0], - ); - break; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]); - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ZRXFeeToken: - takerAssetData = assetDataUtils.encodeERC20AssetData(this._zrxAddress); - break; - case AssetDataScenario.ERC20NonZRXEighteenDecimals: - takerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC721: - takerAssetData = assetDataUtils.encodeERC721AssetData( - this._erc721Token.address, - erc721TakerAssetIds[0], - ); - break; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]); - 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; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; - 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; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - 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; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; - 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; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - 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 = { - 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/test/utils/order_utils.ts b/packages/contracts/test/utils/order_utils.ts deleted file mode 100644 index 4f7a34011..000000000 --- a/packages/contracts/test/utils/order_utils.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { constants } from './constants'; -import { CancelOrder, MatchOrder } from './types'; - -export const orderUtils = { - getPartialAmountFloor(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), - takerAssetFillAmount: takerAssetFillAmount || signedOrder.takerAssetAmount, - signature: signedOrder.signature, - }; - return fill; - }, - createCancel(signedOrder: SignedOrder, takerAssetCancelAmount?: BigNumber): CancelOrder { - const cancel = { - order: orderUtils.getOrderWithoutExchangeAddress(signedOrder), - takerAssetCancelAmount: takerAssetCancelAmount || signedOrder.takerAssetAmount, - }; - return cancel; - }, - getOrderWithoutExchangeAddress(signedOrder: SignedOrder): OrderWithoutExchangeAddress { - const orderStruct = { - senderAddress: signedOrder.senderAddress, - makerAddress: signedOrder.makerAddress, - takerAddress: signedOrder.takerAddress, - feeRecipientAddress: signedOrder.feeRecipientAddress, - makerAssetAmount: signedOrder.makerAssetAmount, - takerAssetAmount: signedOrder.takerAssetAmount, - makerFee: signedOrder.makerFee, - takerFee: signedOrder.takerFee, - expirationTimeSeconds: signedOrder.expirationTimeSeconds, - salt: signedOrder.salt, - makerAssetData: signedOrder.makerAssetData, - takerAssetData: signedOrder.takerAssetData, - }; - return orderStruct; - }, - createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder { - const fill = { - left: orderUtils.getOrderWithoutExchangeAddress(signedOrderLeft), - right: orderUtils.getOrderWithoutExchangeAddress(signedOrderRight), - leftSignature: signedOrderLeft.signature, - rightSignature: signedOrderRight.signature, - }; - fill.right.makerAssetData = constants.NULL_BYTES; - fill.right.takerAssetData = constants.NULL_BYTES; - return fill; - }, -}; diff --git a/packages/contracts/test/utils/profiler.ts b/packages/contracts/test/utils/profiler.ts deleted file mode 100644 index 2c7c1d66c..000000000 --- a/packages/contracts/test/utils/profiler.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let profilerSubprovider: ProfilerSubprovider; - -export const profiler = { - start(): void { - profiler.getProfilerSubproviderSingleton().start(); - }, - stop(): void { - profiler.getProfilerSubproviderSingleton().stop(); - }, - getProfilerSubproviderSingleton(): ProfilerSubprovider { - if (_.isUndefined(profilerSubprovider)) { - profilerSubprovider = profiler._getProfilerSubprovider(); - } - return profilerSubprovider; - }, - _getProfilerSubprovider(): ProfilerSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/packages/contracts/test/utils/revert_trace.ts b/packages/contracts/test/utils/revert_trace.ts deleted file mode 100644 index 3f74fd28b..000000000 --- a/packages/contracts/test/utils/revert_trace.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { devConstants } from '@0x/dev-utils'; -import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov'; -import * as _ from 'lodash'; - -let revertTraceSubprovider: RevertTraceSubprovider; - -export const revertTrace = { - getRevertTraceSubproviderSingleton(): RevertTraceSubprovider { - if (_.isUndefined(revertTraceSubprovider)) { - revertTraceSubprovider = revertTrace._getRevertTraceSubprovider(); - } - return revertTraceSubprovider; - }, - _getRevertTraceSubprovider(): RevertTraceSubprovider { - const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; - const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(); - const isVerbose = true; - const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose); - return subprovider; - }, -}; diff --git a/packages/contracts/test/utils/signing_utils.ts b/packages/contracts/test/utils/signing_utils.ts deleted file mode 100644 index 21f864bfa..000000000 --- a/packages/contracts/test/utils/signing_utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { SignatureType } from '@0x/types'; -import * as ethUtil from 'ethereumjs-util'; - -export const signingUtils = { - signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer { - if (signatureType === SignatureType.EthSign) { - const prefixedMessage = ethUtil.hashPersonalMessage(message); - const ecSignature = ethUtil.ecsign(prefixedMessage, privateKey); - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(signatureType), - ]); - return signature; - } else if (signatureType === SignatureType.EIP712) { - const ecSignature = ethUtil.ecsign(message, privateKey); - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(signatureType), - ]); - return signature; - } else { - throw new Error(`${signatureType} is not a valid signature type`); - } - }, -}; diff --git a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index 64b7dedbe..000000000 --- a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AbstractBalanceAndProxyAllowanceFetcher } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; - -import { AssetWrapper } from './asset_wrapper'; - -export class SimpleAssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { - private readonly _assetWrapper: AssetWrapper; - constructor(assetWrapper: AssetWrapper) { - this._assetWrapper = assetWrapper; - } - public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> { - const balance = await this._assetWrapper.getBalanceAsync(userAddress, assetData); - return balance; - } - public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> { - const proxyAllowance = await this._assetWrapper.getProxyAllowanceAsync(userAddress, assetData); - return proxyAllowance; - } -} diff --git a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts b/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts deleted file mode 100644 index af959e00e..000000000 --- a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { ExchangeWrapper } from './exchange_wrapper'; - -export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { - private readonly _exchangeWrapper: ExchangeWrapper; - private readonly _zrxAssetData: string; - constructor(exchange: ExchangeWrapper, zrxAssetData: string) { - this._exchangeWrapper = exchange; - this._zrxAssetData = zrxAssetData; - } - public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> { - const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash)); - return filledTakerAmount; - } - public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash); - const orderEpoch = await this._exchangeWrapper.getOrderEpochAsync( - signedOrder.makerAddress, - signedOrder.senderAddress, - ); - const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt; - return isCancelled || isCancelledByOrderEpoch; - } - public getZRXAssetData(): string { - return this._zrxAssetData; - } -} diff --git a/packages/contracts/test/utils/test_with_reference.ts b/packages/contracts/test/utils/test_with_reference.ts deleted file mode 100644 index b80be4a6c..000000000 --- a/packages/contracts/test/utils/test_with_reference.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as chai from 'chai'; -import * as _ from 'lodash'; - -import { chaiSetup } from './chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -class Value<T> { - public value: T; - constructor(value: T) { - this.value = value; - } -} - -// tslint:disable-next-line: max-classes-per-file -class ErrorMessage { - public error: string; - constructor(message: string) { - this.error = message; - } -} - -type PromiseResult<T> = Value<T> | ErrorMessage; - -// TODO(albrow): This seems like a generic utility function that could exist in -// lodash. We should replace it by a library implementation, or move it to our -// own. -async function evaluatePromise<T>(promise: Promise<T>): Promise<PromiseResult<T>> { - try { - return new Value<T>(await promise); - } catch (e) { - return new ErrorMessage(e.message); - } -} - -export async function testWithReferenceFuncAsync<P0, R>( - referenceFunc: (p0: P0) => Promise<R>, - testFunc: (p0: P0) => Promise<R>, - values: [P0], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, R>( - referenceFunc: (p0: P0, p1: P1) => Promise<R>, - testFunc: (p0: P0, p1: P1) => Promise<R>, - values: [P0, P1], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>, - values: [P0, P1, P2], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, P3, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>, - values: [P0, P1, P2, P3], -): Promise<void>; -export async function testWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>( - referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>, - values: [P0, P1, P2, P3, P4], -): Promise<void>; - -/** - * Tests the behavior of a test function by comparing it to the expected - * behavior (defined by a reference function). - * - * First the reference function will be called to obtain an "expected result", - * or if the reference function throws/rejects, an "expected error". Next, the - * test function will be called to obtain an "actual result", or if the test - * function throws/rejects, an "actual error". The test passes if at least one - * of the following conditions is met: - * - * 1) Neither the reference function or the test function throw and the - * "expected result" equals the "actual result". - * - * 2) Both the reference function and the test function throw and the "actual - * error" message *contains* the "expected error" message. - * - * @param referenceFuncAsync a reference function implemented in pure - * JavaScript/TypeScript which accepts N arguments and returns the "expected - * result" or throws/rejects with the "expected error". - * @param testFuncAsync a test function which, e.g., makes a call or sends a - * transaction to a contract. It accepts the same N arguments returns the - * "actual result" or throws/rejects with the "actual error". - * @param values an array of N values, where each value corresponds in-order to - * an argument to both the test function and the reference function. - * @return A Promise that resolves if the test passes and rejects if the test - * fails, according to the rules described above. - */ -export async function testWithReferenceFuncAsync( - referenceFuncAsync: (...args: any[]) => Promise<any>, - testFuncAsync: (...args: any[]) => Promise<any>, - values: any[], -): Promise<void> { - // Measure correct behaviour - const expected = await evaluatePromise(referenceFuncAsync(...values)); - - // Measure actual behaviour - const actual = await evaluatePromise(testFuncAsync(...values)); - - // Compare behaviour - if (expected instanceof ErrorMessage) { - // If we expected an error, check if the actual error message contains the - // expected error message. - if (!(actual instanceof ErrorMessage)) { - throw new Error( - `Expected error containing ${expected.error} but got no error\n\tTest case: ${_getTestCaseString( - referenceFuncAsync, - values, - )}`, - ); - } - expect(actual.error).to.contain( - expected.error, - `${actual.error}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`, - ); - } else { - // If we do not expect an error, compare actual and expected directly. - expect(actual).to.deep.equal(expected, `Test case ${_getTestCaseString(referenceFuncAsync, values)}`); - } -} - -function _getTestCaseString(referenceFuncAsync: (...args: any[]) => Promise<any>, values: any[]): string { - const paramNames = _getParameterNames(referenceFuncAsync); - return JSON.stringify(_.zipObject(paramNames, values)); -} - -// Source: https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically -function _getParameterNames(func: (...args: any[]) => any): string[] { - return _.toString(func) - .replace(/[/][/].*$/gm, '') // strip single-line comments - .replace(/\s+/g, '') // strip white space - .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments - .split('){', 1)[0] - .replace(/^[^(]*[(]/, '') // extract the parameters - .replace(/=[^,]+/g, '') // strip any ES6 defaults - .split(',') - .filter(Boolean); // split & filter [""] -} diff --git a/packages/contracts/test/utils/transaction_factory.ts b/packages/contracts/test/utils/transaction_factory.ts deleted file mode 100644 index dbab3ade4..000000000 --- a/packages/contracts/test/utils/transaction_factory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { eip712Utils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { SignatureType } from '@0x/types'; -import { signTypedDataUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; - -import { signingUtils } from './signing_utils'; -import { SignedTransaction } from './types'; - -export class TransactionFactory { - private readonly _signerBuff: Buffer; - private readonly _exchangeAddress: string; - private readonly _privateKey: Buffer; - constructor(privateKey: Buffer, exchangeAddress: string) { - this._privateKey = privateKey; - this._exchangeAddress = exchangeAddress; - this._signerBuff = ethUtil.privateToAddress(this._privateKey); - } - public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction { - const salt = generatePseudoRandomSalt(); - const signerAddress = `0x${this._signerBuff.toString('hex')}`; - const executeTransactionData = { - salt, - signerAddress, - data, - }; - - const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, this._exchangeAddress); - const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData); - const signature = signingUtils.signMessage(eip712MessageBuffer, this._privateKey, signatureType); - const signedTx = { - exchangeAddress: this._exchangeAddress, - signature: `0x${signature.toString('hex')}`, - ...executeTransactionData, - }; - return signedTx; - } -} diff --git a/packages/contracts/test/utils/type_encoding_utils.ts b/packages/contracts/test/utils/type_encoding_utils.ts deleted file mode 100644 index bfd9c9ef5..000000000 --- a/packages/contracts/test/utils/type_encoding_utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import BN = require('bn.js'); -import ethUtil = require('ethereumjs-util'); - -import { constants } from './constants'; - -export const typeEncodingUtils = { - encodeUint256(value: BigNumber): Buffer { - const base = 10; - const formattedValue = new BN(value.toString(base)); - const encodedValue = ethUtil.toBuffer(formattedValue); - // tslint:disable-next-line:custom-no-magic-numbers - const paddedValue = ethUtil.setLengthLeft(encodedValue, constants.WORD_LENGTH); - return paddedValue; - }, - decodeUint256(encodedValue: Buffer): BigNumber { - const formattedValue = ethUtil.bufferToHex(encodedValue); - const value = new BigNumber(formattedValue, constants.BASE_16); - return value; - }, -}; diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts deleted file mode 100644 index 9fc9e1570..000000000 --- a/packages/contracts/test/utils/types.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { OrderWithoutExchangeAddress } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { AbiDefinition } from 'ethereum-types'; - -export interface ERC20BalancesByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: BigNumber; - }; -} - -export interface ERC721TokenIdsByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: BigNumber[]; - }; -} - -export interface SubmissionContractEventArgs { - transactionId: BigNumber; -} - -export interface BatchFillOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - takerAssetFillAmounts: BigNumber[]; -} - -export interface MarketSellOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - takerAssetFillAmount: BigNumber; -} - -export interface MarketBuyOrders { - orders: OrderWithoutExchangeAddress[]; - signatures: string[]; - makerAssetFillAmount: BigNumber; -} - -export interface BatchCancelOrders { - orders: OrderWithoutExchangeAddress[]; -} - -export interface CancelOrdersBefore { - salt: BigNumber; -} - -export interface TransactionDataParams { - name: string; - abi: AbiDefinition[]; - args: any[]; -} - -export interface MultiSigConfig { - owners: string[]; - confirmationsRequired: number; - secondsRequired: number; -} - -export interface MultiSigConfigByNetwork { - [networkName: string]: MultiSigConfig; -} - -export interface Token { - address?: string; - name: string; - symbol: string; - decimals: number; - ipfsHash: string; - swarmHash: string; -} - -export enum OrderStatus { - INVALID, - INVALID_MAKER_ASSET_AMOUNT, - INVALID_TAKER_ASSET_AMOUNT, - FILLABLE, - EXPIRED, - FULLY_FILLED, - CANCELLED, -} - -export enum ContractName { - TokenRegistry = 'TokenRegistry', - MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock', - Exchange = 'Exchange', - ZRXToken = 'ZRXToken', - DummyERC20Token = 'DummyERC20Token', - EtherToken = 'WETH9', - AssetProxyOwner = 'AssetProxyOwner', - AccountLevels = 'AccountLevels', - EtherDelta = 'EtherDelta', - Arbitrage = 'Arbitrage', - TestAssetDataDecoders = 'TestAssetDataDecoders', - TestAssetProxyDispatcher = 'TestAssetProxyDispatcher', - TestLibs = 'TestLibs', - TestSignatureValidator = 'TestSignatureValidator', - ERC20Proxy = 'ERC20Proxy', - ERC721Proxy = 'ERC721Proxy', - DummyERC721Receiver = 'DummyERC721Receiver', - DummyERC721Token = 'DummyERC721Token', - TestLibBytes = 'TestLibBytes', - TestWallet = 'TestWallet', - Authorizable = 'Authorizable', - Whitelist = 'Whitelist', - Forwarder = 'Forwarder', -} - -export interface SignedTransaction { - exchangeAddress: string; - salt: BigNumber; - signerAddress: string; - data: string; - signature: string; -} - -export interface TransferAmountsByMatchOrders { - // Left Maker - amountBoughtByLeftMaker: BigNumber; - amountSoldByLeftMaker: BigNumber; - feePaidByLeftMaker: BigNumber; - // Right Maker - amountBoughtByRightMaker: BigNumber; - amountSoldByRightMaker: BigNumber; - feePaidByRightMaker: BigNumber; - // Taker - amountReceivedByTaker: BigNumber; - feePaidByTakerLeft: BigNumber; - feePaidByTakerRight: BigNumber; -} - -export interface TransferAmountsLoggedByMatchOrders { - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: string; - takerAssetFilledAmount: string; - makerFeePaid: string; - takerFeePaid: string; -} - -export interface OrderInfo { - orderStatus: number; - orderHash: string; - orderTakerAssetFilledAmount: BigNumber; -} - -export interface CancelOrder { - order: OrderWithoutExchangeAddress; - takerAssetCancelAmount: BigNumber; -} - -export interface MatchOrder { - left: OrderWithoutExchangeAddress; - right: OrderWithoutExchangeAddress; - leftSignature: string; - rightSignature: string; -} - -// Combinatorial testing types - -export enum FeeRecipientAddressScenario { - BurnAddress = 'BURN_ADDRESS', - EthUserAddress = 'ETH_USER_ADDRESS', -} - -export enum OrderAssetAmountScenario { - Zero = 'ZERO', - Large = 'LARGE', - Small = 'SMALL', -} - -export enum TakerScenario { - CorrectlySpecified = 'CORRECTLY_SPECIFIED', - IncorrectlySpecified = 'INCORRECTLY_SPECIFIED', - Unspecified = 'UNSPECIFIED', -} - -export enum ExpirationTimeSecondsScenario { - InPast = 'IN_PAST', - InFuture = 'IN_FUTURE', -} - -export enum AssetDataScenario { - ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS', - ZRXFeeToken = 'ZRX_FEE_TOKEN', - ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', - ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', - ERC721 = 'ERC721', -} - -export enum TakerAssetFillAmountScenario { - Zero = 'ZERO', - GreaterThanRemainingFillableTakerAssetAmount = '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 { - takerScenario: TakerScenario; - feeRecipientScenario: FeeRecipientAddressScenario; - makerAssetAmountScenario: OrderAssetAmountScenario; - takerAssetAmountScenario: OrderAssetAmountScenario; - makerFeeScenario: OrderAssetAmountScenario; - takerFeeScenario: OrderAssetAmountScenario; - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario; - makerAssetDataScenario: AssetDataScenario; - takerAssetDataScenario: AssetDataScenario; -} - -export enum BalanceAmountScenario { - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', -} - -export enum AllowanceAmountScenario { - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', - Unlimited = 'UNLIMITED', -} - -export interface TraderStateScenario { - traderAssetBalance: BalanceAmountScenario; - traderAssetAllowance: AllowanceAmountScenario; - zrxFeeBalance: BalanceAmountScenario; - zrxFeeAllowance: AllowanceAmountScenario; -} - -export interface FillScenario { - orderScenario: OrderScenario; - takerAssetFillAmountScenario: TakerAssetFillAmountScenario; - makerStateScenario: TraderStateScenario; - takerStateScenario: TraderStateScenario; -} - -export interface FillResults { - makerAssetFilledAmount: BigNumber; - takerAssetFilledAmount: BigNumber; - makerFeePaid: BigNumber; - takerFeePaid: BigNumber; -} diff --git a/packages/contracts/test/utils/web3_wrapper.ts b/packages/contracts/test/utils/web3_wrapper.ts deleted file mode 100644 index f7b1a732a..000000000 --- a/packages/contracts/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { devConstants, env, EnvVars, web3Factory } from '@0x/dev-utils'; -import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; - -import { coverage } from './coverage'; -import { profiler } from './profiler'; -import { revertTrace } from './revert_trace'; - -enum ProviderType { - Ganache = 'ganache', - Geth = 'geth', -} - -let testProvider: ProviderType; -switch (process.env.TEST_PROVIDER) { - case undefined: - testProvider = ProviderType.Ganache; - break; - case 'ganache': - testProvider = ProviderType.Ganache; - break; - case 'geth': - testProvider = ProviderType.Geth; - break; - default: - throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`); -} - -const ganacheTxDefaults = { - from: devConstants.TESTRPC_FIRST_ADDRESS, - gas: devConstants.GAS_LIMIT, -}; -const gethTxDefaults = { - from: devConstants.TESTRPC_FIRST_ADDRESS, -}; -export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults; - -const gethConfigs = { - shouldUseInProcessGanache: false, - rpcUrl: 'http://localhost:8501', - shouldUseFakeGasEstimate: false, -}; -const ganacheConfigs = { - shouldUseInProcessGanache: true, -}; -const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs; - -export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs); -const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); -const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler); -const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace); -const enabledSubproviderCount = _.filter( - [isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled], - _.identity.bind(_), -).length; -if (enabledSubproviderCount > 1) { - throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`); -} -if (isCoverageEnabled) { - const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); - prependSubprovider(provider, coverageSubprovider); -} -if (isProfilerEnabled) { - if (testProvider === ProviderType.Ganache) { - logUtils.warn( - "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth", - ); - process.exit(1); - } - const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); - logUtils.log( - "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards", - ); - profilerSubprovider.stop(); - prependSubprovider(provider, profilerSubprovider); -} -if (isRevertTraceEnabled) { - const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton(); - prependSubprovider(provider, revertTraceSubprovider); -} - -export const web3Wrapper = new Web3Wrapper(provider); |