aboutsummaryrefslogtreecommitdiffstats
path: root/contracts/core/test/exchange
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2018-12-11 06:37:48 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2018-12-11 06:44:49 +0800
commit9f5eeed30930eea59e9922569a15cb5d689f3eeb (patch)
tree74dac8603dae440bcaa28245fd5af49815284840 /contracts/core/test/exchange
parent14ea4ee1d3fd1a34c1747b928d9b463787e603e7 (diff)
downloaddexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar.gz
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar.bz2
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar.lz
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar.xz
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.tar.zst
dexon-sol-tools-9f5eeed30930eea59e9922569a15cb5d689f3eeb.zip
Rename core package to protocol
Diffstat (limited to 'contracts/core/test/exchange')
-rw-r--r--contracts/core/test/exchange/core.ts1178
-rw-r--r--contracts/core/test/exchange/dispatcher.ts284
-rw-r--r--contracts/core/test/exchange/fill_order.ts314
-rw-r--r--contracts/core/test/exchange/internal.ts472
-rw-r--r--contracts/core/test/exchange/match_orders.ts1284
-rw-r--r--contracts/core/test/exchange/signature_validator.ts526
-rw-r--r--contracts/core/test/exchange/transactions.ts466
-rw-r--r--contracts/core/test/exchange/wrapper.ts1461
8 files changed, 0 insertions, 5985 deletions
diff --git a/contracts/core/test/exchange/core.ts b/contracts/core/test/exchange/core.ts
deleted file mode 100644
index 9b948f991..000000000
--- a/contracts/core/test/exchange/core.ts
+++ /dev/null
@@ -1,1178 +0,0 @@
-import { artifacts as interfacesArtifacts, IAssetDataContract } from '@0x/contracts-interfaces';
-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);
-const assetDataInterface = new IAssetDataContract(
- interfacesArtifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-// 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).sub(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.add(signedOrders[3].makerAssetAmount);
- const fillTakerAssetAmount = signedOrders[2].takerAssetAmount.add(signedOrders[3].takerAssetAmount);
- const makerFee = signedOrders[2].makerFee.add(signedOrders[3].makerFee);
- const takerFee = signedOrders[2].takerFee.add(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].add(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].add(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].add(makerFee.add(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 = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- 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 = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- 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 = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- 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 = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- 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 = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- 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.FULLY_FILLED;
- 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.FULLY_FILLED;
- 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.INVALID_MAKER_ASSET_AMOUNT;
- 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.INVALID_TAKER_ASSET_AMOUNT;
- 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/core/test/exchange/dispatcher.ts b/contracts/core/test/exchange/dispatcher.ts
deleted file mode 100644
index 5b1ac1e20..000000000
--- a/contracts/core/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].add(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/core/test/exchange/fill_order.ts b/contracts/core/test/exchange/fill_order.ts
deleted file mode 100644
index 2bdbe4855..000000000
--- a/contracts/core/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/core/test/exchange/internal.ts b/contracts/core/test/exchange/internal.ts
deleted file mode 100644
index 972f5efb6..000000000
--- a/contracts/core/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.mul(target);
- const remainder = product.mod(denominator);
- const remainderTimes1000 = remainder.mul('1000');
- const isError = remainderTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (remainderTimes1000.greaterThan(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.mul(target);
- const remainder = product.mod(denominator);
- const error = denominator.sub(remainder).mod(denominator);
- const errorTimes1000 = error.mul('1000');
- const isError = errorTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (errorTimes1000.greaterThan(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.mul(target);
- if (product.greaterThan(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.add(singleVal);
- if (newTotal.greaterThan(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.mul(target);
- if (product.greaterThan(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.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(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.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(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.add(orderTakerAssetFilledAmount);
- if (totalFilledAmount.greaterThan(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/core/test/exchange/match_orders.ts b/contracts/core/test/exchange/match_orders.ts
deleted file mode 100644
index 8e943c237..000000000
--- a/contracts/core/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/core/test/exchange/signature_validator.ts b/contracts/core/test/exchange/signature_validator.ts
deleted file mode 100644
index 62579cdc7..000000000
--- a/contracts/core/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/core/test/exchange/transactions.ts b/contracts/core/test/exchange/transactions.ts
deleted file mode 100644
index 746f3cb04..000000000
--- a/contracts/core/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].add(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].add(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].add(makerFeePaid.add(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.add(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.add(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].add(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].add(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].add(makerFeePaid.add(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].add(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].add(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].add(makerFeePaid.add(takerFeePaid)),
- );
- });
- });
-});
diff --git a/contracts/core/test/exchange/wrapper.ts b/contracts/core/test/exchange/wrapper.ts
deleted file mode 100644
index c9efb0c9d..000000000
--- a/contracts/core/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].add(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].add(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].add(makerFee.add(takerFee)),
- );
- });
-
- it('should throw if a signedOrder is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).sub(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].add(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].add(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].add(makerFee.add(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].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- 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
- ].add(makerFee.add(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].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- 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
- ].add(makerFee.add(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].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- 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
- ].add(makerFee.add(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].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- 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
- ].add(makerFee.add(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.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(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].add(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].add(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].add(makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(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].add(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].add(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].add(makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(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].add(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].add(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].add(makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(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].add(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].add(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].add(makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(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
- ].add(signedOrder.makerFee.add(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.FULLY_FILLED;
- 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.FULLY_FILLED;
- 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