aboutsummaryrefslogtreecommitdiffstats
path: root/contracts/protocol/test
diff options
context:
space:
mode:
authorHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
committerHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
commit7ae38906926dc09bc10670c361af0d2bf0050426 (patch)
tree5fb10ae366b987db09e4ddb4bc3ba0f75404ad08 /contracts/protocol/test
parentb5fd3c72a08aaa6957917d74c333387a16edf66b (diff)
downloaddexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.gz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.bz2
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.lz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.xz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.zst
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.zip
Update dependency packages
Diffstat (limited to 'contracts/protocol/test')
-rw-r--r--contracts/protocol/test/asset_proxy/authorizable.ts211
-rw-r--r--contracts/protocol/test/asset_proxy/proxies.ts1285
-rw-r--r--contracts/protocol/test/exchange/core.ts1157
-rw-r--r--contracts/protocol/test/exchange/dispatcher.ts284
-rw-r--r--contracts/protocol/test/exchange/fill_order.ts314
-rw-r--r--contracts/protocol/test/exchange/internal.ts472
-rw-r--r--contracts/protocol/test/exchange/match_orders.ts1284
-rw-r--r--contracts/protocol/test/exchange/signature_validator.ts526
-rw-r--r--contracts/protocol/test/exchange/transactions.ts466
-rw-r--r--contracts/protocol/test/exchange/wrapper.ts1461
-rw-r--r--contracts/protocol/test/global_hooks.ts17
-rw-r--r--contracts/protocol/test/multisig/asset_proxy_owner.ts506
-rw-r--r--contracts/protocol/test/utils/asset_proxy_owner_wrapper.ts70
-rw-r--r--contracts/protocol/test/utils/asset_wrapper.ts222
-rw-r--r--contracts/protocol/test/utils/erc20_wrapper.ts179
-rw-r--r--contracts/protocol/test/utils/erc721_wrapper.ts236
-rw-r--r--contracts/protocol/test/utils/exchange_wrapper.ts292
-rw-r--r--contracts/protocol/test/utils/fill_order_combinatorial_utils.ts928
-rw-r--r--contracts/protocol/test/utils/index.ts3
-rw-r--r--contracts/protocol/test/utils/match_order_tester.ts564
-rw-r--r--contracts/protocol/test/utils/order_factory_from_scenario.ts294
-rw-r--r--contracts/protocol/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts19
-rw-r--r--contracts/protocol/test/utils/simple_order_filled_cancelled_fetcher.ts31
-rw-r--r--contracts/protocol/test/utils/types.ts8
24 files changed, 0 insertions, 10829 deletions
diff --git a/contracts/protocol/test/asset_proxy/authorizable.ts b/contracts/protocol/test/asset_proxy/authorizable.ts
deleted file mode 100644
index 853d18be0..000000000
--- a/contracts/protocol/test/asset_proxy/authorizable.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import {
- chaiSetup,
- constants,
- expectTransactionFailedAsync,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { artifacts } from '../../src/artifacts';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Authorizable', () => {
- let owner: string;
- let notOwner: string;
- let address: string;
- let authorizable: MixinAuthorizableContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- [owner, address, notOwner] = _.slice(accounts, 0, 3);
- authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('addAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should allow owner to add an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.true();
- });
- it('should throw if owner attempts to authorize a duplicate address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- RevertReason.TargetAlreadyAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
-
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddressAtIndex', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should throw if index is >= authorities.length', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(1);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.IndexOutOfBounds,
- );
- });
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- it('should throw if address at index does not match target', async () => {
- const address1 = address;
- const address2 = notOwner;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address1, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address2, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const address1Index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
- from: owner,
- }),
- RevertReason.AuthorizedAddressMismatch,
- );
- });
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
- });
-
- describe('getAuthorizedAddresses', () => {
- it('should return all authorized addresses', async () => {
- const initial = await authorizable.getAuthorizedAddresses.callAsync();
- expect(initial).to.have.length(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterAdd).to.have.length(1);
- expect(afterAdd).to.include(address);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterRemove).to.have.length(0);
- });
- });
-});
diff --git a/contracts/protocol/test/asset_proxy/proxies.ts b/contracts/protocol/test/asset_proxy/proxies.ts
deleted file mode 100644
index c34be9c6a..000000000
--- a/contracts/protocol/test/asset_proxy/proxies.ts
+++ /dev/null
@@ -1,1285 +0,0 @@
-import { artifacts as interfacesArtifacts, IAssetDataContract, IAssetProxyContract } from '@0x/contracts-interfaces';
-import {
- chaiSetup,
- constants,
- expectTransactionFailedAsync,
- expectTransactionFailedWithoutReasonAsync,
- LogDecoder,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokensArtifacts,
- DummyERC20TokenContract,
- DummyERC20TokenTransferEventArgs,
- DummyERC721ReceiverContract,
- DummyERC721TokenContract,
- DummyMultipleReturnERC20TokenContract,
- DummyNoReturnERC20TokenContract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetProxyInterface = new IAssetProxyContract(
- interfacesArtifacts.IAssetProxy.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-const assetDataInterface = new IAssetDataContract(
- interfacesArtifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-
-// tslint:disable:no-unnecessary-type-assertion
-describe('Asset Transfer Proxies', () => {
- let owner: string;
- let notAuthorized: string;
- let authorized: string;
- let fromAddress: string;
- let toAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let erc721TokenA: DummyERC721TokenContract;
- let erc721TokenB: DummyERC721TokenContract;
- let erc721Receiver: DummyERC721ReceiverContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract;
- let multiAssetProxy: MultiAssetProxyContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc721AFromTokenId: BigNumber;
- let erc721BFromTokenId: BigNumber;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- // Deploy AssetProxies
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
- artifacts.MultiAssetProxy,
- provider,
- txDefaults,
- );
-
- // Configure ERC20Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure ERC721Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure MultiAssetProxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Deploy and configure ERC20 tokens
- const numDummyErc20ToDeploy = 2;
- [erc20TokenA, erc20TokenB] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- multipleReturnErc20Token = await DummyMultipleReturnERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.DummyMultipleReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
-
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(fromAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: fromAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multipleReturnErc20Token.setBalance.sendTransactionAsync(
- fromAddress,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multipleReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: fromAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Deploy and configure ERC721 tokens and receiver
- [erc721TokenA, erc721TokenB] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
- tokensArtifacts.DummyERC721Receiver,
- provider,
- txDefaults,
- );
-
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0];
- erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0];
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('ERC20Proxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc20Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0xf47261b0', async () => {
- const proxyId = await erc20Proxy.getProxyId.callAsync();
- const expectedProxyId = '0xf47261b0';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should successfully transfer tokens', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(amount),
- );
- });
-
- it('should successfully transfer tokens that do not return a value', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
- // Perform a transfer from fromAddress to toAddress
- const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance.minus(amount));
- expect(newToBalance).to.be.bignumber.equal(initialToBalance.plus(amount));
- });
-
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- // Construct ERC20 asset data
- const extraData = '0102030405060708';
- const encodedAssetData = `${assetDataUtils.encodeERC20AssetData(erc20TokenA.address)}${extraData}`;
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(amount),
- );
- });
-
- it('should do nothing if transferring 0 amount of a token', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address],
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address],
- );
- });
-
- it('should revert if allowances are too low', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Create allowance less than transfer amount. Set allowance on proxy.
- const allowance = new BigNumber(0);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should revert if allowances are too low and token does not return a value', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
- // Create allowance less than transfer amount. Set allowance on proxy.
- const allowance = new BigNumber(0);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
- expect(newToBalance).to.be.bignumber.equal(initialToBalance);
- });
-
- it('should revert if caller is not authorized', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should revert if token returns more than 32 bytes', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(multipleReturnErc20Token.address);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- const initialFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
- const initialToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
- const newToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
- expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
- expect(newToBalance).to.be.bignumber.equal(initialToBalance);
- });
- });
- });
-
- describe('ERC721Proxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc721Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0x02571792', async () => {
- const proxyId = await erc721Proxy.getProxyId.callAsync();
- const expectedProxyId = '0x02571792';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should successfully transfer tokens', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
- });
-
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- // Construct ERC721 asset data
- const extraData = '0102030405060708';
- const encodedAssetData = `${assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId,
- )}${extraData}`;
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
- });
-
- it('should not call onERC721Received when transferring to a smart contract', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- erc721Receiver.address,
- amount,
- );
- const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts });
- const tx = await logDecoder.getTxWithDecodedLogsAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- );
- // Verify that no log was emitted by erc721 receiver
- expect(tx.logs.length).to.be.equal(1);
- // Verify transfer was successful
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.bignumber.equal(erc721Receiver.address);
- });
-
- it('should revert if transferring 0 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if transferring > 1 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(500);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if allowances are too low', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Remove transfer approval for fromAddress.
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721TokenA.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721AFromTokenId, {
- from: fromAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Perform a transfer; expect this to fail.
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: authorized,
- }),
- RevertReason.TransferFailed,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
-
- it('should revert if caller is not authorized', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- // Verify pre-condition
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- // Perform a transfer from fromAddress to toAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- fromAddress,
- toAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwner).to.be.equal(ownerFromAsset);
- });
- });
- });
- describe('MultiAssetProxy', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: multiAssetProxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- it('should have an id of 0x94cfcdd7', async () => {
- const proxyId = await multiAssetProxy.getProxyId.callAsync();
- // first 4 bytes of `keccak256('MultiAsset(uint256[],bytes[])')`
- const expectedProxyId = '0x94cfcdd7';
- expect(proxyId).to.equal(expectedProxyId);
- });
- describe('transferFrom', () => {
- it('should transfer a single ERC20 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount),
- );
- });
- it('should dispatch an ERC20 transfer when input amount is 0', async () => {
- const inputAmount = constants.ZERO_AMOUNT;
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts });
- const tx = await logDecoder.getTxWithDecodedLogsAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- );
- expect(tx.logs.length).to.be.equal(1);
- const log = tx.logs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>;
- const transferEventName = 'Transfer';
- expect(log.event).to.equal(transferEventName);
- expect(log.args._value).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
- it('should successfully transfer multiple of the same ERC20 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2));
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount),
- );
- });
- it('should successfully transfer multiple different ERC20 tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount),
- );
- });
- it('should transfer a single ERC721 token', async () => {
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc721Amount];
- const nestedAssetData = [erc721AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer multiple of the same ERC721 token', async () => {
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId2,
- );
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const amounts = [erc721Amount, erc721Amount];
- const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- });
- it('should successfully transfer multiple different ERC721 tokens', async () => {
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
- const inputAmount = new BigNumber(1);
- const erc721Amount = new BigNumber(1);
- const amounts = [erc721Amount, erc721Amount];
- const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_TRANSFER_FROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- });
- it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount),
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const extraData = '0102030405060708';
- const assetData = `${assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`;
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset).to.be.equal(fromAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalAmount = inputAmount.times(erc20Amount);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount),
- );
- const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(newOwnerFromAsset).to.be.equal(toAddress);
- });
- it('should successfully transfer correct amounts when the `amount` > 1', async () => {
- const inputAmount = new BigNumber(100);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const amounts = [erc20Amount1, erc20Amount2];
- const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount),
- );
- });
- it('should successfully transfer a large amount of tokens', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount1 = new BigNumber(10);
- const erc20Amount2 = new BigNumber(20);
- const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
- const erc721Amount = new BigNumber(1);
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
- const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1];
- const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
- erc721TokenA.address,
- erc721AFromTokenId2,
- );
- const erc721AssetData3 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
- const erc721AssetData4 = assetDataUtils.encodeERC721AssetData(
- erc721TokenB.address,
- erc721BFromTokenId2,
- );
- const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount];
- const nestedAssetData = [
- erc721AssetData1,
- erc20AssetData1,
- erc721AssetData2,
- erc20AssetData2,
- erc721AssetData3,
- erc721AssetData4,
- ];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- expect(ownerFromAsset1).to.be.equal(fromAddress);
- const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- expect(ownerFromAsset2).to.be.equal(fromAddress);
- const ownerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- expect(ownerFromAsset3).to.be.equal(fromAddress);
- const ownerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
- expect(ownerFromAsset4).to.be.equal(fromAddress);
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
- const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
- const newOwnerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
- const newOwnerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
- expect(newOwnerFromAsset1).to.be.equal(toAddress);
- expect(newOwnerFromAsset2).to.be.equal(toAddress);
- expect(newOwnerFromAsset3).to.be.equal(toAddress);
- expect(newOwnerFromAsset4).to.be.equal(toAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const totalErc20AAmount = inputAmount.times(erc20Amount1);
- const totalErc20BAmount = inputAmount.times(erc20Amount2);
- expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
- );
- expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount),
- );
- expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
- );
- expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
- erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount),
- );
- });
- it('should revert if a single transfer fails', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- // 2 is an invalid erc721 amount
- const erc721Amount = new BigNumber(2);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.InvalidAmount,
- );
- });
- it('should revert if an AssetProxy is not registered', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const invalidProxyId = '0x12345678';
- const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
- // HACK: This is used to get around validation built into assetDataUtils
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.AssetProxyDoesNotExist,
- );
- });
- it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- // HACK: This is used to get around validation built into assetDataUtils
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.LengthMismatch,
- );
- });
- it('should revert if amounts multiplication results in an overflow', async () => {
- const inputAmount = new BigNumber(2).pow(128);
- const erc20Amount = new BigNumber(2).pow(128);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const amounts = [erc20Amount];
- const nestedAssetData = [erc20AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.Uint256Overflow,
- );
- });
- it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = '0x123456';
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- // HACK: This is used to get around validation built into assetDataUtils
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: authorized,
- }),
- RevertReason.LengthGreaterThan3Required,
- );
- });
- it('should revert if caller is not authorized', async () => {
- const inputAmount = new BigNumber(1);
- const erc20Amount = new BigNumber(10);
- const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
- const erc721Amount = new BigNumber(1);
- const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
- const amounts = [erc20Amount, erc721Amount];
- const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- assetData,
- fromAddress,
- toAddress,
- inputAmount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: multiAssetProxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
-// tslint:disable:max-file-line-count
diff --git a/contracts/protocol/test/exchange/core.ts b/contracts/protocol/test/exchange/core.ts
deleted file mode 100644
index f88be1c94..000000000
--- a/contracts/protocol/test/exchange/core.ts
+++ /dev/null
@@ -1,1157 +0,0 @@
-import {
- chaiSetup,
- constants,
- ERC20BalancesByOwner,
- expectTransactionFailedAsync,
- getLatestBlockTimestampAsync,
- increaseTimeAndMineBlockAsync,
- OrderFactory,
- OrderStatus,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokensArtifacts,
- DummyERC20TokenContract,
- DummyERC20TokenTransferEventArgs,
- DummyERC721TokenContract,
- DummyNoReturnERC20TokenContract,
- ReentrantERC20TokenContract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated-wrappers/exchange';
-import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
-import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('Exchange core', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let multiAssetProxy: MultiAssetProxyContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
-
- let signedOrder: SignedOrder;
- let erc20Balances: ERC20BalancesByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetIds: BigNumber[];
- let erc721TakerAssetIds: BigNumber[];
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- // Deploy AssetProxies, Exchange, tokens, and malicious contracts
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
- artifacts.MultiAssetProxy,
- provider,
- txDefaults,
- );
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- // Configure ERC20Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure ERC721Proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure MultiAssetProxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- // Configure Exchange
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
-
- // Configure ERC20 tokens
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- // Configure ERC721 tokens
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
- erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
-
- // Configure order defaults
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should throw if signature is invalid', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
-
- const v = ethUtil.toBuffer(signedOrder.signature.slice(0, 4));
- const invalidR = ethUtil.sha3('invalidR');
- const invalidS = ethUtil.sha3('invalidS');
- const signatureType = ethUtil.toBuffer(`0x${signedOrder.signature.slice(-2)}`);
- const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
- const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
- signedOrder.signature = invalidSigHex;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if no value is filled', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Wallet', async () => {
- const maliciousMakerAddress = maliciousWallet.address;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.setBalance.sendTransactionAsync(
- maliciousMakerAddress,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await maliciousWallet.approveERC20.sendTransactionAsync(
- erc20TokenA.address,
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAddress: maliciousMakerAddress,
- makerFee: constants.ZERO_AMOUNT,
- });
- signedOrder.signature = `0x0${SignatureType.Wallet}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.WalletError,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Validator', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- isApproved,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.ValidatorError,
- );
- });
-
- it('should not emit transfer events for transfers where from == to', async () => {
- const txReceipt = await exchangeWrapper.fillOrderAsync(signedOrder, makerAddress);
- const logs = txReceipt.logs;
- const transferLogs = _.filter(
- logs,
- log => (log as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).event === 'Transfer',
- );
- expect(transferLogs.length).to.be.equal(2);
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.makerFee);
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.takerFee);
- });
- });
-
- describe('Testing exchange of ERC20 tokens with no return values', () => {
- before(async () => {
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(makerAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should throw if not sent by maker', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidMaker,
- );
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should be able to cancel a full order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- }),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should log 1 event with correct arguments', async () => {
- const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- expect(res.logs).to.have.length(1);
-
- const log = res.logs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>;
- const logArgs = log.args;
-
- expect(signedOrder.makerAddress).to.be.equal(logArgs.makerAddress);
- expect(signedOrder.makerAddress).to.be.equal(logArgs.senderAddress);
- expect(signedOrder.feeRecipientAddress).to.be.equal(logArgs.feeRecipientAddress);
- expect(signedOrder.makerAssetData).to.be.equal(logArgs.makerAssetData);
- expect(signedOrder.takerAssetData).to.be.equal(logArgs.takerAssetData);
- expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
- });
-
- it('should throw if already cancelled', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if order is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
- });
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if rounding error is greater than 0.1%', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1001),
- takerAssetAmount: new BigNumber(3),
- });
-
- const fillTakerAssetAmount1 = new BigNumber(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount1,
- });
-
- const fillTakerAssetAmount2 = new BigNumber(1);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount2,
- }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- it('should fail to set orderEpoch less than current orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- const lesserOrderEpoch = new BigNumber(0);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should fail to set orderEpoch equal to existing orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should cancel only orders with a orderEpoch less than existing orderEpoch', async () => {
- // Cancel all transactions with a orderEpoch less than 1
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
-
- // Create 3 orders with orderEpoch values: 0,1,2,3
- // Since we cancelled with orderEpoch=1, orders with orderEpoch<=1 will not be processed
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const signedOrders = [
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- salt: new BigNumber(0),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- salt: new BigNumber(1),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- salt: new BigNumber(2),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- salt: new BigNumber(3),
- }),
- ];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.plus(signedOrders[3].makerAssetAmount);
- const fillTakerAssetAmount = signedOrders[2].takerAssetAmount.plus(signedOrders[3].takerAssetAmount);
- const makerFee = signedOrders[2].makerFee.plus(signedOrders[3].makerFee);
- const takerFee = signedOrders[2].takerFee.plus(signedOrders[3].takerFee);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(fillMakerAssetAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(fillTakerAssetAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(fillTakerAssetAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(fillMakerAssetAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
- });
-
- describe('Testing Exchange of ERC721 Tokens', () => {
- it('should throw when maker does not own the token with id makerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721TakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.not.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when taker does not own the token with id takerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721MakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when makerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(2),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw when takerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(500),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw on partial fill', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- });
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('Testing exchange of multiple assets', () => {
- it('should allow multiple assets to be exchanged for a single asset', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
- const makerAssetAmount = new BigNumber(1);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const takerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.plus(takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(takerAssetAmount));
- });
- it('should allow multiple assets to be exchanged for multiple assets', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
- const makerAssetAmount = new BigNumber(1);
- const takerAmounts = [new BigNumber(10), new BigNumber(1)];
- const takerAssetId = erc721TakerAssetIds[0];
- const takerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- ];
- const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
- const takerAssetAmount = new BigNumber(1);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.plus(takerAmounts[0].times(takerAssetAmount)),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.minus(takerAmounts[0].times(takerAssetAmount)),
- );
- expect(finalOwnerTakerAsset).to.be.equal(makerAddress);
- });
- it('should allow an order selling multiple assets to be partially filled', async () => {
- const makerAmounts = [new BigNumber(10), new BigNumber(20)];
- const makerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
- const makerAssetAmount = new BigNumber(30);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const takerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.minus(
- makerAmounts[0].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.minus(
- makerAmounts[1].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.plus(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.plus(
- makerAmounts[0].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.plus(
- makerAmounts[1].times(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.minus(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- });
- it('should allow an order buying multiple assets to be partially filled', async () => {
- const takerAmounts = [new BigNumber(10), new BigNumber(20)];
- const takerNestedAssetData = [
- assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
- ];
- const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
- const takerAssetAmount = new BigNumber(30);
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = new BigNumber(10);
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- takerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- makerFee: constants.ZERO_AMOUNT,
- takerFee: constants.ZERO_AMOUNT,
- });
-
- const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(
- initialMakerBalanceA.plus(
- takerAmounts[0].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerBalanceB).to.be.bignumber.equal(
- initialMakerBalanceB.plus(
- takerAmounts[1].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalMakerZrxBalance).to.be.bignumber.equal(
- initialMakerZrxBalance.minus(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- expect(finalTakerBalanceA).to.be.bignumber.equal(
- initialTakerBalanceA.minus(
- takerAmounts[0].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerBalanceB).to.be.bignumber.equal(
- initialTakerBalanceB.minus(
- takerAmounts[1].times(
- takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- ),
- );
- expect(finalTakerZrxBalance).to.be.bignumber.equal(
- initialTakerZrxBalance.plus(
- makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
- ),
- );
- });
- });
-
- describe('getOrderInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should return the correct orderInfo for an unfilled valid order', async () => {
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Fillable;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FullyFilled;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.Fillable;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and unfilled order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Cancelled;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.Cancelled;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and unfilled order', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Expired;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.Expired;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- // FULLY_FILLED takes precedence over EXPIRED
- const expectedOrderStatus = OrderStatus.FullyFilled;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a makerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.InvalidMakerAssetAmount;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a takerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ takerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.InvalidTakerAssetAmount;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/protocol/test/exchange/dispatcher.ts b/contracts/protocol/test/exchange/dispatcher.ts
deleted file mode 100644
index eca1b38f1..000000000
--- a/contracts/protocol/test/exchange/dispatcher.ts
+++ /dev/null
@@ -1,284 +0,0 @@
-import {
- chaiSetup,
- constants,
- expectTransactionFailedAsync,
- LogDecoder,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { DummyERC20TokenContract } from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId, RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import {
- TestAssetProxyDispatcherAssetProxyRegisteredEventArgs,
- TestAssetProxyDispatcherContract,
-} from '../../generated-wrappers/test_asset_proxy_dispatcher';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyDispatcher', () => {
- let owner: string;
- let notOwner: string;
- let makerAddress: string;
- let takerAddress: string;
-
- let zrxToken: DummyERC20TokenContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let assetProxyDispatcher: TestAssetProxyDispatcherContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Setup accounts & addresses
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 1;
- [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS);
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
-
- assetProxyDispatcher = await TestAssetProxyDispatcherContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyDispatcher,
- provider,
- txDefaults,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('registerAssetProxy', () => {
- it('should record proxy upon registration', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should be able to record multiple proxies', async () => {
- // Record first proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- let proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Record another proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC721);
- expect(proxyAddress).to.be.equal(erc721Proxy.address);
- });
-
- it('should throw if a proxy with the same id is already registered', async () => {
- // Initial registration
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Deploy a new version of the ERC20 Transfer Proxy contract
- const newErc20TransferProxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC20Proxy,
- provider,
- txDefaults,
- );
- // Register new ERC20 Transfer Proxy contract
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
- from: owner,
- }),
- RevertReason.AssetProxyAlreadyExists,
- );
- });
-
- it('should throw if requesting address is not owner', async () => {
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should log an event with correct arguments when an asset proxy is registered', async () => {
- const logDecoder = new LogDecoder(web3Wrapper, artifacts);
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- );
- const logs = txReceipt.logs;
- const log = logs[0] as LogWithDecodedArgs<TestAssetProxyDispatcherAssetProxyRegisteredEventArgs>;
- expect(log.args.id).to.equal(AssetProxyId.ERC20);
- expect(log.args.assetProxy).to.equal(erc20Proxy.address);
- });
- });
-
- describe('getAssetProxy', () => {
- it('should return correct address of registered proxy', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should return NULL address if requesting non-existent proxy', async () => {
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('dispatchTransferFrom', () => {
- it('should dispatch transfer to registered proxy', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(amount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(amount),
- );
- });
-
- it('should not dispatch a transfer if amount == 0', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = constants.ZERO_AMOUNT;
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should not dispatch a transfer if from == to', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- makerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should throw if dispatching to unregistered proxy', async () => {
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(10);
- return expectTransactionFailedAsync(
- assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- RevertReason.AssetProxyDoesNotExist,
- );
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/protocol/test/exchange/fill_order.ts b/contracts/protocol/test/exchange/fill_order.ts
deleted file mode 100644
index 2bdbe4855..000000000
--- a/contracts/protocol/test/exchange/fill_order.ts
+++ /dev/null
@@ -1,314 +0,0 @@
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- chaiSetup,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- provider,
- TakerAssetFillAmountScenario,
- TakerScenario,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import * as _ from 'lodash';
-
-import {
- FillOrderCombinatorialUtils,
- fillOrderCombinatorialUtilsFactoryAsync,
-} from '../utils/fill_order_combinatorial_utils';
-
-chaiSetup.configure();
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const defaultFillScenario = {
- orderScenario: {
- takerScenario: TakerScenario.Unspecified,
- feeRecipientScenario: FeeRecipientAddressScenario.EthUserAddress,
- makerAssetAmountScenario: OrderAssetAmountScenario.Large,
- takerAssetAmountScenario: OrderAssetAmountScenario.Large,
- makerFeeScenario: OrderAssetAmountScenario.Large,
- takerFeeScenario: OrderAssetAmountScenario.Large,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InFuture,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
- takerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
-};
-
-describe('FillOrder Tests', () => {
- let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrder', () => {
- const test = (fillScenarios: FillScenario[]) => {
- _.forEach(fillScenarios, fillScenario => {
- const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
- it(description, async () => {
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
- };
-
- const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations();
- describe('Combinatorially generated fills orders', () => test(allFillScenarios));
-
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.CorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should throw when taker is specified and order is claimed by other', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.IncorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetFillAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if an order is expired', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-
- describe('Testing exchange of ERC721 Tokens', () => {
- it('should successfully exchange a single token between the maker and taker (via fillOrder)', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
- });
-
- it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and approveAll is set for it', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset and takerAsset are ERC721 and approveAll is set for them', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- takerStateScenario: {
- ...defaultFillScenario.takerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-});
diff --git a/contracts/protocol/test/exchange/internal.ts b/contracts/protocol/test/exchange/internal.ts
deleted file mode 100644
index 6ff1fdc2f..000000000
--- a/contracts/protocol/test/exchange/internal.ts
+++ /dev/null
@@ -1,472 +0,0 @@
-import {
- bytes32Values,
- chaiSetup,
- constants,
- FillResults,
- getRevertReasonOrErrorMessageForSendTransactionAsync,
- provider,
- testCombinatoriallyWithReferenceFuncAsync,
- txDefaults,
- uint256Values,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { Order, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
-
-const emptyOrder: Order = {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress: constants.NULL_ADDRESS,
- takerAddress: constants.NULL_ADDRESS,
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- makerAssetAmount: new BigNumber(0),
- takerAssetAmount: new BigNumber(0),
- makerAssetData: '0x',
- takerAssetData: '0x',
- salt: new BigNumber(0),
- exchangeAddress: constants.NULL_ADDRESS,
- feeRecipientAddress: constants.NULL_ADDRESS,
- expirationTimeSeconds: new BigNumber(0),
-};
-
-const emptySignedOrder: SignedOrder = {
- ...emptyOrder,
- signature: '',
-};
-
-const overflowErrorForCall = new Error(RevertReason.Uint256Overflow);
-
-describe('Exchange core internal functions', () => {
- let testExchange: TestExchangeInternalsContract;
- let overflowErrorForSendTransaction: Error | undefined;
- let divisionByZeroErrorForCall: Error | undefined;
- let roundingErrorForCall: Error | undefined;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- overflowErrorForSendTransaction = new Error(
- await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
- );
- divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
- roundingErrorForCall = new Error(RevertReason.RoundingError);
- });
- // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
- // the blockchain state for any tests which modify it!
-
- async function referenceIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.multipliedBy(target);
- const remainder = product.mod(denominator);
- const remainderTimes1000 = remainder.multipliedBy('1000');
- const isError = remainderTimes1000.gte(product);
- if (product.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (remainderTimes1000.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.multipliedBy(target);
- const remainder = product.mod(denominator);
- const error = denominator.minus(remainder).mod(denominator);
- const errorTimes1000 = error.multipliedBy('1000');
- const isError = errorTimes1000.gte(product);
- if (product.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (errorTimes1000.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorFloorAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.multipliedBy(target);
- if (product.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
-
- describe('addFillResults', async () => {
- function makeFillResults(value: BigNumber): FillResults {
- return {
- makerAssetFilledAmount: value,
- takerAssetFilledAmount: value,
- makerFeePaid: value,
- takerFeePaid: value,
- };
- }
- async function referenceAddFillResultsAsync(
- totalValue: BigNumber,
- singleValue: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here, each of totalFillResults and
- // singleFillResults will consist of fields with the same values.
- // This should be safe because none of the fields in a given
- // FillResults are ever used together in a mathemetical operation.
- // They are only used with the corresponding field from *the other*
- // FillResults, which are different.
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- // HACK(albrow): _.mergeWith mutates the first argument! To
- // workaround this we use _.cloneDeep.
- return _.mergeWith(
- _.cloneDeep(totalFillResults),
- singleFillResults,
- (totalVal: BigNumber, singleVal: BigNumber) => {
- const newTotal = totalVal.plus(singleVal);
- if (newTotal.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return newTotal;
- },
- );
- }
- async function testAddFillResultsAsync(totalValue: BigNumber, singleValue: BigNumber): Promise<FillResults> {
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- return testExchange.publicAddFillResults.callAsync(totalFillResults, singleFillResults);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'addFillResults',
- referenceAddFillResultsAsync,
- testAddFillResultsAsync,
- [uint256Values, uint256Values],
- );
- });
-
- describe('calculateFillResults', async () => {
- function makeOrder(
- makerAssetAmount: BigNumber,
- takerAssetAmount: BigNumber,
- makerFee: BigNumber,
- takerFee: BigNumber,
- ): Order {
- return {
- ...emptyOrder,
- makerAssetAmount,
- takerAssetAmount,
- makerFee,
- takerFee,
- };
- }
- async function referenceCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here we are re-using the same value (otherAmount)
- // for order.makerAssetAmount, order.makerFee, and order.takerFee.
- // This should be safe because they are never used with each other
- // in any mathematical operation in either the reference TypeScript
- // implementation or the Solidity implementation of
- // calculateFillResults.
- const makerAssetFilledAmount = await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- );
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- const orderMakerAssetAmount = order.makerAssetAmount;
- return {
- makerAssetFilledAmount,
- takerAssetFilledAmount,
- makerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- makerAssetFilledAmount,
- orderMakerAssetAmount,
- otherAmount,
- ),
- takerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- ),
- };
- }
- async function testCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- return testExchange.publicCalculateFillResults.callAsync(order, takerAssetFilledAmount);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'calculateFillResults',
- referenceCalculateFillResultsAsync,
- testCalculateFillResultsAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountFloor', async () => {
- async function referenceGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.multipliedBy(target);
- if (product.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
- async function testGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountFloor',
- referenceGetPartialAmountFloorAsync,
- testGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountCeil', async () => {
- async function referenceGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.multipliedBy(target);
- const offset = product.plus(denominator.minus(1));
- if (offset.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.multipliedBy(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.multipliedBy(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountCeil',
- referenceGetPartialAmountCeilAsync,
- testGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountFloor', async () => {
- async function testSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountFloor',
- referenceSafeGetPartialAmountFloorAsync,
- testSafeGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountCeil', async () => {
- async function referenceSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorCeilAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.multipliedBy(target);
- const offset = product.plus(denominator.minus(1));
- if (offset.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.multipliedBy(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.multipliedBy(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountCeil',
- referenceSafeGetPartialAmountCeilAsync,
- testSafeGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorFloor', async () => {
- async function testIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorFloor',
- referenceIsRoundingErrorFloorAsync,
- testIsRoundingErrorFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorCeil', async () => {
- async function testIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorCeil',
- referenceIsRoundingErrorCeilAsync,
- testIsRoundingErrorCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('updateFilledState', async () => {
- // Note(albrow): Since updateFilledState modifies the state by calling
- // sendTransaction, we must reset the state after each test.
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- async function referenceUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- // tslint:disable-next-line:no-unused-variable
- orderHash: string,
- ): Promise<BigNumber> {
- const totalFilledAmount = takerAssetFilledAmount.plus(orderTakerAssetFilledAmount);
- if (totalFilledAmount.isGreaterThan(MAX_UINT256)) {
- throw overflowErrorForSendTransaction;
- }
- return totalFilledAmount;
- }
- async function testUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- orderHash: string,
- ): Promise<BigNumber> {
- const fillResults = {
- makerAssetFilledAmount: new BigNumber(0),
- takerAssetFilledAmount,
- makerFeePaid: new BigNumber(0),
- takerFeePaid: new BigNumber(0),
- };
- await web3Wrapper.awaitTransactionSuccessAsync(
- await testExchange.publicUpdateFilledState.sendTransactionAsync(
- emptySignedOrder,
- constants.NULL_ADDRESS,
- orderHash,
- orderTakerAssetFilledAmount,
- fillResults,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return testExchange.filled.callAsync(orderHash);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'updateFilledState',
- referenceUpdateFilledStateAsync,
- testUpdateFilledStateAsync,
- [uint256Values, uint256Values, bytes32Values],
- );
- });
-});
diff --git a/contracts/protocol/test/exchange/match_orders.ts b/contracts/protocol/test/exchange/match_orders.ts
deleted file mode 100644
index 8e943c237..000000000
--- a/contracts/protocol/test/exchange/match_orders.ts
+++ /dev/null
@@ -1,1284 +0,0 @@
-import {
- chaiSetup,
- constants,
- ERC20BalancesByOwner,
- ERC721TokenIdsByOwner,
- expectTransactionFailedAsync,
- OrderFactory,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokensArtifacts,
- DummyERC20TokenContract,
- DummyERC721TokenContract,
- ReentrantERC20TokenContract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { MatchOrderTester } from '../utils/match_order_tester';
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('matchOrders', () => {
- let makerAddressLeft: string;
- let makerAddressRight: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddressLeft: string;
- let feeRecipientAddressRight: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
-
- let erc20BalancesByOwner: ERC20BalancesByOwner;
- let erc721TokenIdsByOwner: ERC721TokenIdsByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactoryLeft: OrderFactory;
- let orderFactoryRight: OrderFactory;
-
- let erc721LeftMakerAssetIds: BigNumber[];
- let erc721RightMakerAssetIds: BigNumber[];
-
- let defaultERC20MakerAssetAddress: string;
- let defaultERC20TakerAssetAddress: string;
- let defaultERC721AssetAddress: string;
-
- let matchOrderTester: MatchOrderTester;
-
- let testExchange: TestExchangeInternalsContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Create accounts
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
- // but that is invalid syntax as of TypeScript version >= 2.8. We don't
- // have the right fine-grained configuration options in TSLint,
- // Prettier, or TypeScript, to reconcile this, so we will just have to
- // wait for them to sort it out. We disable TSLint and Prettier for
- // this part of the code for now. This occurs several times in this
- // file. See https://github.com/prettier/prettier/issues/4624.
- // prettier-ignore
- const usedAddresses = ([
- owner,
- makerAddressLeft,
- makerAddressRight,
- takerAddress,
- feeRecipientAddressLeft,
- // tslint:disable-next-line:trailing-comma
- feeRecipientAddressRight
- ] = _.slice(accounts, 0, 6));
- // Create wrappers
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
- // Deploy ERC20 token & ERC20 proxy
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- // Deploy ERC721 token and proxy
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
- erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
- // Depoy exchange
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
- // Authorize ERC20 and ERC721 trades by exchange
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- // Set default addresses
- defaultERC20MakerAssetAddress = erc20TokenA.address;
- defaultERC20TakerAssetAddress = erc20TokenB.address;
- defaultERC721AssetAddress = erc721Token.address;
- // Create default order parameters
- const defaultOrderParamsLeft = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressLeft,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressLeft,
- };
- const defaultOrderParamsRight = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressRight,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressRight,
- };
- const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
- orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
- const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
- orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
- // Set match order tester
- matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, zrxToken.address);
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('matchOrders', () => {
- beforeEach(async () => {
- erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
- erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
- });
-
- it('Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error ceil & not rounding error floor
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the left maker will sell.
- const numerator = signedOrderLeft.makerAssetAmount;
- const denominator = signedOrderLeft.takerAssetAmount;
- const target = signedOrderRight.makerAssetAmount;
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.true();
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the left maker received a slightly better sell price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the left maker received a slightly more favorable sell price, the fee
- // paid by the left taker is slightly higher than that paid by the left maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(14), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error floor & not rounding error ceil
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the right maker will buy.
- const numerator = signedOrderRight.takerAssetAmount;
- const denominator = signedOrderRight.makerAssetAmount;
- const target = signedOrderLeft.takerAssetAmount;
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.true();
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the right maker received a slightly better purchase price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the right maker received a slightly more favorable buy price, the fee
- // paid by the right taker is slightly higher than that paid by the right maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.7835051546391752'), 16), // 92.78%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.8571428571428571'), 16), // 92.85%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker a better buy price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The correct price buy price for the right maker would yield (49/83) * 22 = 12.988 units
- // of the left maker asset. This gets rounded up to 13, giving the right maker a better price.
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5060240963855421'), 16), // 26.506%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5306122448979591'), 16), // 26.531%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker a better sell price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a fee
- // slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker and right taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2650), 0), // 2650.6 rounded down tro 2650
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(2653), 0), // 2653.1 rounded down to 2653
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker and left taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a
- // fee slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9166), 0), // 9166.6 rounded down to 9166
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(9175), 0), // 9175.2 rounded down to 9175
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2126), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1063), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- // Notes:
- // i.
- // The left order is fully filled by the right order, so the right maker must sell 1005 units of their asset to the left maker.
- // By selling 1005 units, the right maker should theoretically receive 502.5 units of the left maker's asset.
- // Since the transfer amount must be an integer, this value must be rounded down to 502 or up to 503.
- // ii.
- // If the right order were filled via `Exchange.fillOrder` the respective fill amounts would be [1004, 502] or [1006, 503].
- // It follows that we cannot trigger a sale of 1005 units of the right maker's asset through `Exchange.fillOrder`.
- // iii.
- // For an optimal match, the algorithm must choose either [1005, 502] or [1005, 503] as fill amounts for the right order.
- // The algorithm favors the right maker when the exchange rate must be rounded, so the final fill for the right order is [1005, 503].
- // iv.
- // The right maker fee differs from the right taker fee because their exchange rate differs.
- // The right maker always receives the better exchange and fee price.
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(503), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.2718720602069614'), 16), // 47.27%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(497), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.3189087488240827'), 16), // 47.31%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow matchOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- takerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('matchOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts when orders completely fill each other', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when left order is completely filled and right order is partially filled', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- // Construct second right order
- // Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "left fill"
- // branch in the contract twice for this test.
- const signedOrderRight2 = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft with signedOrderRight2
- const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount;
- const rightTakerAssetFilledAmount = new BigNumber(0);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight2,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
-
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(6), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
-
- // Create second left order
- // Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "right fill"
- // branch in the contract twice for this test.
- const signedOrderLeft2 = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft2 with signedOrderRight
- const leftTakerAssetFilledAmount = new BigNumber(0);
- const takerAmountReceived = newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress].minus(
- erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
- );
- const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft2,
- signedOrderRight,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => {
- const feeRecipientAddress = feeRecipientAddressLeft;
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feeRecipientAddress,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress,
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left order maker', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = signedOrderLeft.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right order maker', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = signedOrderRight.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = feeRecipientAddressLeft;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = feeRecipientAddressRight;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if left maker is the left fee recipient and right maker is the right fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should throw if left order is not fillable', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Cancel left order
- await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('Should throw if right order is not fillable', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Cancel right order
- await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if there is not a positive spread', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.NegativeSpreadRequired,
- );
- });
-
- it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- // We are assuming assetData fields of the right order are the
- // reverse of the left order, rather than checking equality. This
- // saves a bunch of gas, but as a result if the assetData fields are
- // off then the failure ends up happening at signature validation
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if the right maker asset is not equal to the left taker asset', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/contracts/protocol/test/exchange/signature_validator.ts b/contracts/protocol/test/exchange/signature_validator.ts
deleted file mode 100644
index 3f1786b5b..000000000
--- a/contracts/protocol/test/exchange/signature_validator.ts
+++ /dev/null
@@ -1,526 +0,0 @@
-import { artifacts as examplesArtifacts, ValidatorContract, WalletContract } from '@0x/contracts-examples';
-import {
- addressUtils,
- chaiSetup,
- constants,
- expectContractCallFailedAsync,
- LogDecoder,
- OrderFactory,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-
-import {
- artifacts,
- TestSignatureValidatorContract,
- TestSignatureValidatorSignatureValidatorApprovalEventArgs,
- TestStaticCallReceiverContract,
-} from '../../src';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('MixinSignatureValidator', () => {
- let signedOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let signatureValidator: TestSignatureValidatorContract;
- let testWallet: WalletContract;
- let testValidator: ValidatorContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
- let signerAddress: string;
- let signerPrivateKey: Buffer;
- let notSignerAddress: string;
- let notSignerPrivateKey: Buffer;
- let signatureValidatorLogDecoder: LogDecoder;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const makerAddress = accounts[0];
- signerAddress = makerAddress;
- notSignerAddress = accounts[1];
- signatureValidator = await TestSignatureValidatorContract.deployFrom0xArtifactAsync(
- artifacts.TestSignatureValidator,
- provider,
- txDefaults,
- );
- testWallet = await WalletContract.deployFrom0xArtifactAsync(
- examplesArtifacts.Wallet,
- provider,
- txDefaults,
- signerAddress,
- );
- testValidator = await ValidatorContract.deployFrom0xArtifactAsync(
- examplesArtifacts.Validator,
- provider,
- txDefaults,
- signerAddress,
- );
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- signatureValidatorLogDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, {
- from: signerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- true,
- {
- from: signerAddress,
- },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: signatureValidator.address,
- makerAddress,
- feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
- makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- };
- signerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- notSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(notSignerAddress)];
- orderFactory = new OrderFactory(signerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('isValidSignature', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should revert when signature is empty', async () => {
- const emptySignature = '0x';
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- emptySignature,
- ),
- RevertReason.LengthGreaterThan0Required,
- );
- });
-
- it('should revert when signature type is unsupported', async () => {
- const unsupportedSignatureType = SignatureType.NSignatureTypes;
- const unsupportedSignatureHex = `0x${Buffer.from([unsupportedSignatureType]).toString('hex')}`;
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureUnsupported,
- );
- });
-
- it('should revert when SignatureType=Illegal', async () => {
- const unsupportedSignatureHex = `0x${Buffer.from([SignatureType.Illegal]).toString('hex')}`;
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureIllegal,
- );
- });
-
- it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
- const signatureHex = `0x${Buffer.from([SignatureType.Invalid]).toString('hex')}`;
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when SignatureType=Invalid and signature length is non-zero', async () => {
- const fillerData = ethUtil.toBuffer('0xdeadbeef');
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Invalid}`);
- const signatureBuffer = Buffer.concat([fillerData, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signatureBuffer);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- ),
- RevertReason.Length0Required,
- );
- });
-
- it('should return true when SignatureType=EIP712 and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EIP712 and signature is invalid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=EthSign and signature is valid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EthSign and signature is invalid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Wallet and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Wallet and signature is invalid', async () => {
- // Create EIP712 signature using a private key that does not belong to the wallet owner.
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const notWalletOwnerPrivateKey = notSignerPrivateKey;
- const ecSignature = ethUtil.ecsign(orderHashBuffer, notWalletOwnerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Wallet', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- maliciousWallet.address,
- signatureHex,
- ),
- RevertReason.WalletError,
- );
- });
-
- it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- // This will return false because we signed the message with `signerAddress`, but
- // are validating against `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Validator', async () => {
- const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex),
- RevertReason.ValidatorError,
- );
- });
- it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
- // Set approval of signature validator to false
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- false,
- { from: signerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate signature
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
- // Presign hash
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.preSign.sendTransactionAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signedOrder.signature,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate presigned signature
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Presigned and signer has not presigned hash', async () => {
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when message was signed by a Trezor One (firmware version 1.6.2)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0xc28b145f10f0bcf0fc000e778615f8fd73490bad';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x7b888b596ccf87f0bacab0dcb483124973f7420f169b4824d7a12534ac1e9832');
- const s = ethUtil.toBuffer('0x0c8e14f7edc01459e13965f1da56e0c23ed11e2cca932571eee1292178f90424');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return true when message was signed by a Trezor Model T (firmware version 2.0.7)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0x98ce6d9345e8ffa7d99ee0822272fae9d2c0e895';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f');
- const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
- });
-
- describe('setSignatureValidatorApproval', () => {
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is approved', async () => {
- const approval = true;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is disapproved', async () => {
- const approval = false;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/protocol/test/exchange/transactions.ts b/contracts/protocol/test/exchange/transactions.ts
deleted file mode 100644
index e8c775f3e..000000000
--- a/contracts/protocol/test/exchange/transactions.ts
+++ /dev/null
@@ -1,466 +0,0 @@
-import { artifacts as examplesArtifacts, ExchangeWrapperContract, WhitelistContract } from '@0x/contracts-examples';
-import {
- chaiSetup,
- constants,
- ERC20BalancesByOwner,
- expectTransactionFailedAsync,
- OrderFactory,
- orderUtils,
- provider,
- SignedTransaction,
- TransactionFactory,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { DummyERC20TokenContract } from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange transactions', () => {
- let senderAddress: string;
- let owner: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
-
- let erc20Balances: ERC20BalancesByOwner;
- let signedOrder: SignedOrder;
- let signedTx: SignedTransaction;
- let orderWithoutExchangeAddress: OrderWithoutExchangeAddress;
- let orderFactory: OrderFactory;
- let makerTransactionFactory: TransactionFactory;
- let takerTransactionFactory: TransactionFactory;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
-
- let defaultMakerTokenAddress: string;
- let defaultTakerTokenAddress: string;
- let makerPrivateKey: Buffer;
- let takerPrivateKey: Buffer;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = _.slice(
- accounts,
- 0,
- 5,
- ));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- defaultMakerTokenAddress = erc20TokenA.address;
- defaultTakerTokenAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
- orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
- takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
- });
- describe('executeTransaction', () => {
- describe('fillOrder', () => {
- let takerAssetFillAmount: BigNumber;
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
-
- takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should transfer the correct amounts when signed by taker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
-
- it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
- RevertReason.InvalidTxHash,
- );
- });
-
- it('should reset the currentContextAddress', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const currentContextAddress = await exchange.currentContextAddress.callAsync();
- expect(currentContextAddress).to.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- const data = exchange.cancelOrder.getABIEncodedTransactionData(orderWithoutExchangeAddress);
- signedTx = makerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should cancel the order when signed by maker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- let exchangeWrapperContract: ExchangeWrapperContract;
-
- before(async () => {
- exchangeWrapperContract = await ExchangeWrapperContract.deployFrom0xArtifactAsync(
- examplesArtifacts.ExchangeWrapper,
- provider,
- txDefaults,
- exchange.address,
- );
- });
-
- it("should cancel an order if called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.plus(1);
- const cancelData = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetOrderEpoch);
- const signedCancelTx = makerTransactionFactory.newSignedTransaction(cancelData);
- await exchangeWrapperContract.cancelOrdersUpTo.sendTransactionAsync(
- targetOrderEpoch,
- signedCancelTx.salt,
- signedCancelTx.signature,
- {
- from: makerAddress,
- },
- );
-
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const fillData = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData);
- return expectTransactionFailedAsync(
- exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedFillTx.salt,
- signedOrder.signature,
- signedFillTx.signature,
- { from: takerAddress },
- ),
- RevertReason.FailedExecution,
- );
- });
-
- it("should not cancel an order if not called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.plus(1);
- await exchangeWrapper.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress);
-
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- await exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedTx.salt,
- signedOrder.signature,
- signedTx.signature,
- { from: takerAddress },
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- });
- });
-
- describe('Whitelist', () => {
- let whitelist: WhitelistContract;
- let whitelistOrderFactory: OrderFactory;
-
- before(async () => {
- whitelist = await WhitelistContract.deployFrom0xArtifactAsync(
- examplesArtifacts.Whitelist,
- provider,
- txDefaults,
- exchange.address,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(whitelist.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress: whitelist.address,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- signedOrder = await whitelistOrderFactory.newSignedOrderAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
-
- it('should revert if maker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.MakerNotWhitelisted,
- );
- });
-
- it('should revert if taker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.TakerNotWhitelisted,
- );
- });
-
- it('should fill the order if maker and taker have been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFillAmount = signedOrder.makerAssetAmount;
- const makerFeePaid = signedOrder.makerFee;
- const takerFeePaid = signedOrder.takerFee;
-
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)),
- );
- });
- });
-});
diff --git a/contracts/protocol/test/exchange/wrapper.ts b/contracts/protocol/test/exchange/wrapper.ts
deleted file mode 100644
index 49ba5a2e5..000000000
--- a/contracts/protocol/test/exchange/wrapper.ts
+++ /dev/null
@@ -1,1461 +0,0 @@
-import {
- chaiSetup,
- constants,
- ERC20BalancesByOwner,
- expectTransactionFailedAsync,
- getLatestBlockTimestampAsync,
- increaseTimeAndMineBlockAsync,
- OrderFactory,
- OrderStatus,
- provider,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import {
- artifacts as tokensArtifacts,
- DummyERC20TokenContract,
- DummyERC721TokenContract,
- ReentrantERC20TokenContract,
-} from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange wrappers', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
-
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetId: BigNumber;
- let erc721TakerAssetId: BigNumber;
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetId = erc721Balances[makerAddress][erc721Token.address][0];
- erc721TakerAssetId = erc721Balances[takerAddress][erc721Token.address][0];
-
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- tokensArtifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrKillOrder', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrKillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrKillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should throw if a signedOrder is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if entire takerAssetFillAmount not filled', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.CompleteFillFailed,
- );
- });
- });
-
- describe('fillOrderNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrderNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('fillOrderNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 250000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
-
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should not change erc20Balances if maker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if maker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker balance', async () => {
- const makerZRXBalance = new BigNumber(erc20Balances[makerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: makerZRXBalance,
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker allowance', async () => {
- const makerZRXAllowance = await zrxToken.allowance.callAsync(makerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(makerZRXAllowance),
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker balance', async () => {
- const takerZRXBalance = new BigNumber(erc20Balances[takerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: takerZRXBalance,
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker allowance', async () => {
- const takerZRXAllowance = await zrxToken.allowance.callAsync(takerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(takerZRXAllowance),
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should successfully exchange ERC721 tokens', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetId;
- const takerAssetId = erc721TakerAssetId;
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 280000,
- });
- // Verify post-conditions
- const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
- const newOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(newOwnerTakerAsset).to.be.bignumber.equal(makerAddress);
- });
- });
-
- describe('batch functions', () => {
- let signedOrders: SignedOrder[];
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
-
- describe('batchFillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][
- takerAssetAddress
- ].plus(takerAssetFillAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][
- makerAssetAddress
- ].plus(makerAssetFilledAmount);
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(makerFee.plus(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchFillOrKillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrKillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrKillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][
- takerAssetAddress
- ].plus(takerAssetFillAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][
- makerAssetAddress
- ].plus(makerAssetFilledAmount);
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(makerFee.plus(takerFee));
- });
-
- await exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw if a single signedOrder does not fill the expected amount', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- });
-
- await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
-
- return expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('batchFillOrdersNoThrow', async () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.batchFillOrdersNoThrowAsync([signedOrder], takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('batchFillOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][
- takerAssetAddress
- ].plus(takerAssetFillAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][
- makerAssetAddress
- ].plus(makerAssetFilledAmount);
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(makerFee.plus(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not throw if an order is invalid and fill the remaining orders', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
-
- const invalidOrder = {
- ...signedOrders[0],
- signature: '0x00',
- };
- const validOrders = signedOrders.slice(1);
-
- takerAssetFillAmounts.push(invalidOrder.takerAssetAmount.div(2));
- _.forEach(validOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][
- takerAssetAddress
- ].plus(takerAssetFillAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][
- makerAssetAddress
- ].plus(makerAssetFilledAmount);
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(makerFee.plus(takerFee));
- });
-
- const newOrders = [invalidOrder, ...validOrders];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
- takerAssetFillAmounts,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 450000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketSellOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketSellOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- // We simply use the takerAssetData from the first order for all orders.
- // If they are not the same, the contract throws when validating the order signature
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketSellOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketSellOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 6000000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketBuyOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketBuyOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketBuyOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketBuyOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].plus(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFee.plus(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
-
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].plus(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].plus(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchCancelOrders', () => {
- it('should be able to cancel multiple signedOrders', async () => {
- const takerAssetCancelAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount);
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts: takerAssetCancelAmounts,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.be.deep.equal(newBalances);
- });
- });
-
- describe('getOrdersInfo', () => {
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
- it('should get the correct information for multiple unfilled orders', async () => {
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Fillable;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.Fillable;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple fully filled orders', async () => {
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FullyFilled;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and unfilled orders', async () => {
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Cancelled;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.Cancelled;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and unfilled orders', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.Expired;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.Expired;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for a mix of unfilled, partially filled, fully filled, cancelled, and expired orders', async () => {
- const unfilledOrder = await orderFactory.newSignedOrderAsync();
- const partiallyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(partiallyFilledOrder, takerAddress, {
- takerAssetFillAmount: partiallyFilledOrder.takerAssetAmount.div(2),
- });
- const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(fullyFilledOrder, takerAddress);
- const cancelledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const expiredOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp),
- });
- signedOrders = [unfilledOrder, partiallyFilledOrder, fullyFilledOrder, cancelledOrder, expiredOrder];
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(5);
-
- const expectedUnfilledOrderHash = orderHashUtils.getOrderHashHex(unfilledOrder);
- const expectedUnfilledTakerAssetFilledAmount = new BigNumber(0);
- const expectedUnfilledOrderStatus = OrderStatus.Fillable;
- const unfilledOrderInfo = ordersInfo[0];
- expect(unfilledOrderInfo.orderHash).to.be.equal(expectedUnfilledOrderHash);
- expect(unfilledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedUnfilledTakerAssetFilledAmount,
- );
- expect(unfilledOrderInfo.orderStatus).to.be.equal(expectedUnfilledOrderStatus);
-
- const expectedPartialOrderHash = orderHashUtils.getOrderHashHex(partiallyFilledOrder);
- const expectedPartialTakerAssetFilledAmount = partiallyFilledOrder.takerAssetAmount.div(2);
- const expectedPartialOrderStatus = OrderStatus.Fillable;
- const partialOrderInfo = ordersInfo[1];
- expect(partialOrderInfo.orderHash).to.be.equal(expectedPartialOrderHash);
- expect(partialOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedPartialTakerAssetFilledAmount,
- );
- expect(partialOrderInfo.orderStatus).to.be.equal(expectedPartialOrderStatus);
-
- const expectedFilledOrderHash = orderHashUtils.getOrderHashHex(fullyFilledOrder);
- const expectedFilledTakerAssetFilledAmount = fullyFilledOrder.takerAssetAmount;
- const expectedFilledOrderStatus = OrderStatus.FullyFilled;
- const filledOrderInfo = ordersInfo[2];
- expect(filledOrderInfo.orderHash).to.be.equal(expectedFilledOrderHash);
- expect(filledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedFilledTakerAssetFilledAmount,
- );
- expect(filledOrderInfo.orderStatus).to.be.equal(expectedFilledOrderStatus);
-
- const expectedCancelledOrderHash = orderHashUtils.getOrderHashHex(cancelledOrder);
- const expectedCancelledTakerAssetFilledAmount = new BigNumber(0);
- const expectedCancelledOrderStatus = OrderStatus.Cancelled;
- const cancelledOrderInfo = ordersInfo[3];
- expect(cancelledOrderInfo.orderHash).to.be.equal(expectedCancelledOrderHash);
- expect(cancelledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedCancelledTakerAssetFilledAmount,
- );
- expect(cancelledOrderInfo.orderStatus).to.be.equal(expectedCancelledOrderStatus);
-
- const expectedExpiredOrderHash = orderHashUtils.getOrderHashHex(expiredOrder);
- const expectedExpiredTakerAssetFilledAmount = new BigNumber(0);
- const expectedExpiredOrderStatus = OrderStatus.Expired;
- const expiredOrderInfo = ordersInfo[4];
- expect(expiredOrderInfo.orderHash).to.be.equal(expectedExpiredOrderHash);
- expect(expiredOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedExpiredTakerAssetFilledAmount,
- );
- expect(expiredOrderInfo.orderStatus).to.be.equal(expectedExpiredOrderStatus);
- });
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/contracts/protocol/test/global_hooks.ts b/contracts/protocol/test/global_hooks.ts
deleted file mode 100644
index f8ace376a..000000000
--- a/contracts/protocol/test/global_hooks.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { env, EnvVars } from '@0x/dev-utils';
-
-import { coverage, profiler, provider } from '@0x/contracts-test-utils';
-before('start web3 provider', () => {
- provider.start();
-});
-after('generate coverage report', async () => {
- if (env.parseBoolean(EnvVars.SolidityCoverage)) {
- const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
- await coverageSubprovider.writeCoverageAsync();
- }
- if (env.parseBoolean(EnvVars.SolidityProfiler)) {
- const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
- await profilerSubprovider.writeProfilerOutputAsync();
- }
- provider.stop();
-});
diff --git a/contracts/protocol/test/multisig/asset_proxy_owner.ts b/contracts/protocol/test/multisig/asset_proxy_owner.ts
deleted file mode 100644
index daebfb7fb..000000000
--- a/contracts/protocol/test/multisig/asset_proxy_owner.ts
+++ /dev/null
@@ -1,506 +0,0 @@
-import {
- chaiSetup,
- constants,
- expectContractCallFailedAsync,
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- expectTransactionFailedWithoutReasonAsync,
- increaseTimeAndMineBlockAsync,
- provider,
- sendTransactionResult,
- txDefaults,
- web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-
-import {
- AssetProxyOwnerAssetProxyRegistrationEventArgs,
- AssetProxyOwnerContract,
- AssetProxyOwnerExecutionEventArgs,
- AssetProxyOwnerExecutionFailureEventArgs,
- AssetProxyOwnerSubmissionEventArgs,
-} from '../../generated-wrappers/asset_proxy_owner';
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { TestAssetProxyOwnerContract } from '../../generated-wrappers/test_asset_proxy_owner';
-import { artifacts } from '../../src/artifacts';
-import { AssetProxyOwnerWrapper } from '../utils/asset_proxy_owner_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyOwner', () => {
- let owners: string[];
- let authorized: string;
- let notOwner: string;
- const REQUIRED_APPROVALS = new BigNumber(2);
- const SECONDS_TIME_LOCKED = new BigNumber(1000000);
-
- let erc20Proxy: MixinAuthorizableContract;
- let erc721Proxy: MixinAuthorizableContract;
- let testAssetProxyOwner: TestAssetProxyOwnerContract;
- let assetProxyOwnerWrapper: AssetProxyOwnerWrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owners = [accounts[0], accounts[1]];
- authorized = accounts[2];
- notOwner = accounts[3];
- const initialOwner = accounts[0];
- erc20Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- erc721Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- const defaultAssetProxyContractAddresses: string[] = [];
- testAssetProxyOwner = await TestAssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyOwner,
- provider,
- txDefaults,
- owners,
- defaultAssetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- assetProxyOwnerWrapper = new AssetProxyOwnerWrapper(testAssetProxyOwner, provider);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('constructor', () => {
- it('should register passed in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, erc721Proxy.address];
- const newMultiSig = await AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- const isErc20ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc20Proxy.address);
- const isErc721ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc721Proxy.address);
- expect(isErc20ProxyRegistered).to.equal(true);
- expect(isErc721ProxyRegistered).to.equal(true);
- });
- it('should throw if a null address is included in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
- return expectContractCreationFailedAsync(
- (AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- ) as any) as sendTransactionResult,
- RevertReason.InvalidAssetProxy,
- );
- });
- });
-
- describe('isFunctionRemoveAuthorizedAddressAtIndex', () => {
- it('should return false if data is not for removeAuthorizedAddressAtIndex', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- owners[0],
- );
-
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- notRemoveAuthorizedAddressData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.false();
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex', async () => {
- const index = new BigNumber(0);
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- owners[0],
- index,
- );
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- removeAuthorizedAddressAtIndexData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.true();
- });
- });
-
- describe('registerAssetProxy', () => {
- it('should throw if not called by multisig', async () => {
- const isRegistered = true;
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, {
- from: owners[0],
- }),
- );
- });
-
- it('should register an address if called by multisig after timelock', async () => {
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
-
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await assetProxyOwnerWrapper.executeTransactionAsync(txId, owners[0]);
- const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerAssetProxyRegistrationEventArgs
- >;
- expect(registerLog.args.assetProxyContract).to.equal(addressToRegister);
- expect(registerLog.args.isRegistered).to.equal(isRegistered);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(isRegistered);
- });
-
- it('should fail if registering a null address', async () => {
- const addressToRegister = constants.NULL_ADDRESS;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await assetProxyOwnerWrapper.executeTransactionAsync(txId, owners[0]);
- const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerExecutionFailureEventArgs>;
- expect(failureLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(false);
- });
- });
-
- describe('Calling removeAuthorizedAddressAtIndex', () => {
- const erc20Index = new BigNumber(0);
- const erc721Index = new BigNumber(1);
- before('authorize both proxies and register erc20 proxy', async () => {
- // Only register ERC20 proxy
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const registerAssetProxySubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const registerAssetProxySubmitLog = registerAssetProxySubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
-
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(authorized);
- const erc20AddAuthorizedAddressSubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc721AddAuthorizedAddressSubmitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc721Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc20AddAuthorizedAddressSubmitLog = erc20AddAuthorizedAddressSubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
- const erc721AddAuthorizedAddressSubmitLog = erc721AddAuthorizedAddressSubmitRes
- .logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
-
- const registerAssetProxyTxId = registerAssetProxySubmitLog.args.transactionId;
- const erc20AddAuthorizedAddressTxId = erc20AddAuthorizedAddressSubmitLog.args.transactionId;
- const erc721AddAuthorizedAddressTxId = erc721AddAuthorizedAddressSubmitLog.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(registerAssetProxyTxId, owners[1]);
- await assetProxyOwnerWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
- await assetProxyOwnerWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
- await assetProxyOwnerWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
- await assetProxyOwnerWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- await assetProxyOwnerWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- });
-
- describe('validRemoveAuthorizedAddressAtIndexTx', () => {
- it('should revert if data is not for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- authorized,
- );
- const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- notRemoveAuthorizedAddressData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- const isValidRemoveAuthorizedAddressAtIndexTx = await testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(
- txId,
- );
- expect(isValidRemoveAuthorizedAddressAtIndexTx).to.be.true();
- });
-
- it('should revert if data is for removeAuthorizedAddressAtIndex and proxy is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const submitTxRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.UnregisteredAssetProxy,
- );
- });
- });
-
- describe('executeRemoveAuthorizedAddressAtIndex', () => {
- it('should throw without the required confirmations', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const res = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.TxNotFullyConfirmed,
- );
- });
-
- it('should throw if tx destination is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const res = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.UnregisteredAssetProxy,
- );
- });
-
- it('should throw if tx data is not for removeAuthorizedAddressAtIndex', async () => {
- const newAuthorized = owners[1];
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- newAuthorized,
- );
- const res = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync(
- txId,
- owners[0],
- );
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by non-owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, notOwner);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should throw if already executed', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await assetProxyOwnerWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await assetProxyOwnerWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await assetProxyOwnerWrapper.executeRemoveAuthorizedAddressAtIndexAsync(
- txId,
- owners[0],
- );
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- );
- });
- });
- });
-});
-// tslint:disable-line max-file-line-count
diff --git a/contracts/protocol/test/utils/asset_proxy_owner_wrapper.ts b/contracts/protocol/test/utils/asset_proxy_owner_wrapper.ts
deleted file mode 100644
index df23658d8..000000000
--- a/contracts/protocol/test/utils/asset_proxy_owner_wrapper.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import { LogDecoder } from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
-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 { artifacts } from '../../src/artifacts';
-
-export class AssetProxyOwnerWrapper {
- private readonly _assetProxyOwner: AssetProxyOwnerContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(assetproxyOwnerContract: AssetProxyOwnerContract, provider: Provider) {
- this._assetProxyOwner = assetproxyOwnerContract;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper, { ...artifacts, ...tokensArtifacts });
- }
- 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._assetProxyOwner.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._assetProxyOwner.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._assetProxyOwner.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._assetProxyOwner.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
- ._assetProxyOwner as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(
- txId,
- {
- from,
- },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
-}
diff --git a/contracts/protocol/test/utils/asset_wrapper.ts b/contracts/protocol/test/utils/asset_wrapper.ts
deleted file mode 100644
index e4090ad74..000000000
--- a/contracts/protocol/test/utils/asset_wrapper.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import { AbstractAssetWrapper, constants } from '@0x/contracts-test-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-import * as _ from 'lodash';
-
-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/contracts/protocol/test/utils/erc20_wrapper.ts b/contracts/protocol/test/utils/erc20_wrapper.ts
deleted file mode 100644
index e5ab0e36c..000000000
--- a/contracts/protocol/test/utils/erc20_wrapper.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts, DummyERC20TokenContract } from '@0x/contracts-tokens';
-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 { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { artifacts } from '../../src/artifacts';
-
-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(
- tokensArtifacts.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/contracts/protocol/test/utils/erc721_wrapper.ts b/contracts/protocol/test/utils/erc721_wrapper.ts
deleted file mode 100644
index 1f658ce86..000000000
--- a/contracts/protocol/test/utils/erc721_wrapper.ts
+++ /dev/null
@@ -1,236 +0,0 @@
-import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts, DummyERC721TokenContract } from '@0x/contracts-tokens';
-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 { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { artifacts } from '../../src/artifacts';
-
-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(
- tokensArtifacts.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/contracts/protocol/test/utils/exchange_wrapper.ts b/contracts/protocol/test/utils/exchange_wrapper.ts
deleted file mode 100644
index 437882b41..000000000
--- a/contracts/protocol/test/utils/exchange_wrapper.ts
+++ /dev/null
@@ -1,292 +0,0 @@
-import {
- FillResults,
- formatters,
- LogDecoder,
- OrderInfo,
- orderUtils,
- SignedTransaction,
-} from '@0x/contracts-test-utils';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
-import { SignedOrder } from '@0x/types';
-import { AbiEncoder, BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { MethodAbi, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { artifacts } from '../../src/artifacts';
-
-import { AbiDecodedFillOrderData } 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, { ...artifacts, ...tokensArtifacts });
- }
- 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);
- 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 abiDecodeFillOrder(data: string): AbiDecodedFillOrderData {
- // Lookup fillOrder ABI in exchange abi
- const fillOrderAbi = _.find(this._exchange.abi, { name: 'fillOrder' }) as MethodAbi;
- // Decode input data
- const abiEncoder = new AbiEncoder.Method(fillOrderAbi);
- const decodedData = abiEncoder.decode(data) as AbiDecodedFillOrderData;
- return decodedData;
- }
- public getExchangeAddress(): string {
- return this._exchange.address;
- }
-}
diff --git a/contracts/protocol/test/utils/fill_order_combinatorial_utils.ts b/contracts/protocol/test/utils/fill_order_combinatorial_utils.ts
deleted file mode 100644
index c2f530e5b..000000000
--- a/contracts/protocol/test/utils/fill_order_combinatorial_utils.ts
+++ /dev/null
@@ -1,928 +0,0 @@
-import { artifacts as libsArtifacts, TestLibsContract } from '@0x/contracts-libs';
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- chaiSetup,
- constants,
- expectTransactionFailedAsync,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- orderUtils,
- signingUtils,
- TakerAssetFillAmountScenario,
- TakerScenario,
- TraderStateScenario,
-} from '@0x/contracts-test-utils';
-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 { artifacts } from '../../src/artifacts';
-
-import { AssetWrapper } from './asset_wrapper';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-import { OrderFactoryFromScenario } from './order_factory_from_scenario';
-import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher';
-import { SimpleOrderFilledCancelledFetcher } from './simple_order_filled_cancelled_fetcher';
-
-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(
- libsArtifacts.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.plus(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 abiDataEncodedByContract = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- const paramsDecodedByClient = this.exchangeWrapper.abiDecodeFillOrder(abiDataEncodedByContract);
- expect(paramsDecodedByClient).to.be.deep.equal(params, '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.plus(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).integerValue(BigNumber.ROUND_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/contracts/protocol/test/utils/index.ts b/contracts/protocol/test/utils/index.ts
deleted file mode 100644
index 75cd88666..000000000
--- a/contracts/protocol/test/utils/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './exchange_wrapper';
-export * from './erc20_wrapper';
-export * from './erc721_wrapper';
diff --git a/contracts/protocol/test/utils/match_order_tester.ts b/contracts/protocol/test/utils/match_order_tester.ts
deleted file mode 100644
index 0ba8017c5..000000000
--- a/contracts/protocol/test/utils/match_order_tester.ts
+++ /dev/null
@@ -1,564 +0,0 @@
-import {
- chaiSetup,
- ERC20BalancesByOwner,
- ERC721TokenIdsByOwner,
- OrderInfo,
- OrderStatus,
- TransferAmountsByMatchOrders as TransferAmounts,
- TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts,
-} from '@0x/contracts-test-utils';
-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 { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-
-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.minus(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.isEqualTo(maxAmountBoughtByLeftMaker)
- ? OrderStatus.FullyFilled
- : OrderStatus.Fillable;
- expect(leftOrderInfo.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.isEqualTo(
- maxAmountBoughtByRightMaker,
- )
- ? OrderStatus.FullyFilled
- : OrderStatus.Fillable;
- expect(rightOrderInfo.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].plus(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- // Taker
- expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- takerAddress
- ][makerAssetAddressLeft].plus(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].plus(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.plus(expectedTransferAmounts.feePaidByTakerRight),
- );
- // Left Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].plus(
- expectedTransferAmounts.feePaidByLeftMaker.plus(expectedTransferAmounts.feePaidByTakerLeft),
- );
- // Right Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressRight][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].plus(
- expectedTransferAmounts.feePaidByRightMaker.plus(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/contracts/protocol/test/utils/order_factory_from_scenario.ts b/contracts/protocol/test/utils/order_factory_from_scenario.ts
deleted file mode 100644
index ecb4b2e28..000000000
--- a/contracts/protocol/test/utils/order_factory_from_scenario.ts
+++ /dev/null
@@ -1,294 +0,0 @@
-import {
- AssetDataScenario,
- constants,
- ERC721TokenIdsByOwner,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- OrderAssetAmountScenario,
- OrderScenario,
- TakerScenario,
-} from '@0x/contracts-test-utils';
-import { DummyERC721TokenContract } from '@0x/contracts-tokens';
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { Order } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-
-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/contracts/protocol/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/contracts/protocol/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts
deleted file mode 100644
index 64b7dedbe..000000000
--- a/contracts/protocol/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/contracts/protocol/test/utils/simple_order_filled_cancelled_fetcher.ts b/contracts/protocol/test/utils/simple_order_filled_cancelled_fetcher.ts
deleted file mode 100644
index af959e00e..000000000
--- a/contracts/protocol/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/contracts/protocol/test/utils/types.ts b/contracts/protocol/test/utils/types.ts
deleted file mode 100644
index 5f12635a7..000000000
--- a/contracts/protocol/test/utils/types.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-export interface AbiDecodedFillOrderData {
- order: SignedOrder;
- takerAssetFillAmount: BigNumber;
- signature: string;
-}