diff options
Diffstat (limited to 'packages/contracts/test/exchange')
-rw-r--r-- | packages/contracts/test/exchange/core.ts | 586 | ||||
-rw-r--r-- | packages/contracts/test/exchange/dispatcher.ts | 206 | ||||
-rw-r--r-- | packages/contracts/test/exchange/fill_order.ts | 305 | ||||
-rw-r--r-- | packages/contracts/test/exchange/libs.ts | 14 | ||||
-rw-r--r-- | packages/contracts/test/exchange/match_orders.ts | 91 | ||||
-rw-r--r-- | packages/contracts/test/exchange/signature_validator.ts | 32 | ||||
-rw-r--r-- | packages/contracts/test/exchange/transactions.ts | 87 | ||||
-rw-r--r-- | packages/contracts/test/exchange/wrapper.ts | 71 |
8 files changed, 591 insertions, 801 deletions
diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index ff652d3aa..db56623f9 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -1,31 +1,28 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils'; -import { AssetProxyId, SignedOrder } from '@0xproject/types'; +import { RevertReason, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import ethUtil = require('ethereumjs-util'); - -import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token'; -import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token'; -import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; -import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy'; -import { - CancelContractEventArgs, - ExchangeContract, - FillContractEventArgs, -} from '../../src/generated_contract_wrappers/exchange'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; -import { ERC721Wrapper } from '../../src/utils/erc721_wrapper'; -import { ExchangeWrapper } from '../../src/utils/exchange_wrapper'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { ERC20BalancesByOwner } from '../../src/utils/types'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import * as _ from 'lodash'; + +import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; +import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c721_token'; +import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_proxy'; +import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; +import { CancelContractEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; +import { OrderFactory } from '../utils/order_factory'; +import { ERC20BalancesByOwner } from '../utils/types'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -66,12 +63,16 @@ describe('Exchange core', () => { }); before(async () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); + const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4)); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); + const numDummyErc20ToDeploy = 3; + [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); @@ -86,11 +87,11 @@ describe('Exchange core', () => { artifacts.Exchange, provider, txDefaults, - zrxToken.address, + assetProxyUtils.encodeERC20AssetData(zrxToken.address), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); await web3Wrapper.awaitTransactionSuccessAsync( await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { @@ -130,295 +131,6 @@ describe('Exchange core', () => { erc20Balances = await erc20Wrapper.getBalancesAsync(); signedOrder = orderFactory.newSignedOrder(); }); - it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => { - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - }); - - const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0); - - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - - const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount); - - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const makerAssetFilledAmount = takerAssetFillAmount - .times(signedOrder.makerAssetAmount) - .dividedToIntegerBy(signedOrder.takerAssetAmount); - const makerFeePaid = signedOrder.makerFee - .times(makerAssetFilledAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - const takerFeePaid = 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(makerFeePaid), - ); - 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(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - - it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => { - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - }); - - const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0); - - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - - const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount); - - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const makerAssetFilledAmount = takerAssetFillAmount - .times(signedOrder.makerAssetAmount) - .dividedToIntegerBy(signedOrder.takerAssetAmount); - const makerFeePaid = signedOrder.makerFee - .times(makerAssetFilledAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - const takerFeePaid = 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(makerFeePaid), - ); - 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(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - - it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => { - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - }); - - const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0); - - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - - const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount); - - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const makerAssetFilledAmount = takerAssetFillAmount - .times(signedOrder.makerAssetAmount) - .dividedToIntegerBy(signedOrder.takerAssetAmount); - const makerFeePaid = signedOrder.makerFee - .times(makerAssetFilledAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - const takerFeePaid = 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(makerFeePaid), - ); - 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(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - - it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => { - signedOrder = orderFactory.newSignedOrder({ - takerAddress, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - }); - - const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0); - - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - - const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - const expectedMakerAmountBoughtAfter = takerAssetFillAmount.add(takerAssetFilledAmountBefore); - expect(makerAmountBoughtAfter).to.be.bignumber.equal(expectedMakerAmountBoughtAfter); - - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const makerAssetFilledAmount = takerAssetFillAmount - .times(signedOrder.makerAssetAmount) - .dividedToIntegerBy(signedOrder.takerAssetAmount); - const makerFeePaid = signedOrder.makerFee - .times(makerAssetFilledAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - const takerFeePaid = 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(makerFeePaid), - ); - 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(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - - it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => { - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - - const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { - takerAssetFillAmount: signedOrder.takerAssetAmount, - }); - const log = res.logs[0] as LogWithDecodedArgs<FillContractEventArgs>; - expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal( - signedOrder.takerAssetAmount.minus(takerAssetFillAmount), - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(signedOrder.makerAssetAmount), - ); - expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultTakerAssetAddress].add(signedOrder.takerAssetAmount), - ); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(signedOrder.makerFee), - ); - expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultTakerAssetAddress].minus(signedOrder.takerAssetAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].add(signedOrder.makerAssetAmount), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].minus(signedOrder.takerFee), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add( - signedOrder.makerFee.add(signedOrder.takerFee), - ), - ); - }); - - it('should log 1 event with the correct arguments when order has a feeRecipient', async () => { - const divisor = 2; - const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { - takerAssetFillAmount: signedOrder.takerAssetAmount.div(divisor), - }); - expect(res.logs).to.have.length(1); - - const log = res.logs[0] as LogWithDecodedArgs<FillContractEventArgs>; - const logArgs = log.args; - const expectedFilledMakerAssetAmount = signedOrder.makerAssetAmount.div(divisor); - const expectedFilledTakerAssetAmount = signedOrder.takerAssetAmount.div(divisor); - const expectedFeeMPaid = signedOrder.makerFee.div(divisor); - const expectedFeeTPaid = signedOrder.takerFee.div(divisor); - - expect(signedOrder.makerAddress).to.be.equal(logArgs.makerAddress); - expect(takerAddress).to.be.equal(logArgs.takerAddress); - expect(takerAddress).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(expectedFilledMakerAssetAmount).to.be.bignumber.equal(logArgs.makerAssetFilledAmount); - expect(expectedFilledTakerAssetAmount).to.be.bignumber.equal(logArgs.takerAssetFilledAmount); - expect(expectedFeeMPaid).to.be.bignumber.equal(logArgs.makerFeePaid); - expect(expectedFeeTPaid).to.be.bignumber.equal(logArgs.takerFeePaid); - expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash); - }); - - it('should throw when taker is specified and order is claimed by other', async () => { - signedOrder = orderFactory.newSignedOrder({ - takerAddress: feeRecipientAddress, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - }); - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); it('should throw if signature is invalid', async () => { signedOrder = orderFactory.newSignedOrder({ @@ -432,98 +144,18 @@ describe('Exchange core', () => { const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]); const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`; signedOrder.signature = invalidSigHex; - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if makerAssetAmount is 0', async () => { - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: new BigNumber(0), - }); - - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if takerAssetAmount is 0', async () => { - signedOrder = orderFactory.newSignedOrder({ - takerAssetAmount: new BigNumber(0), - }); - - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if takerAssetFillAmount is 0', async () => { - signedOrder = orderFactory.newSignedOrder(); - - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { - takerAssetFillAmount: new BigNumber(0), - }), - ); - }); - - it('should throw if maker erc20Balances are too low to fill order', async () => { - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18), - }); - - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if taker erc20Balances are too low to fill order', async () => { - signedOrder = orderFactory.newSignedOrder({ - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18), - }); - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if maker allowances are too low to fill order', async () => { - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if taker allowances are too low to fill order', async () => { - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - return expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - ); - }); - - it('should throw if an order is expired', async () => { - signedOrder = orderFactory.newSignedOrder({ - expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), - }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + RevertReason.InvalidOrderSignature, ); }); it('should throw if no value is filled', async () => { signedOrder = orderFactory.newSignedOrder(); await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + RevertReason.OrderUnfillable, ); }); }); @@ -535,8 +167,9 @@ describe('Exchange core', () => { }); it('should throw if not sent by maker', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress), + RevertReason.InvalidMaker, ); }); @@ -545,8 +178,9 @@ describe('Exchange core', () => { makerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + RevertReason.OrderUnfillable, ); }); @@ -555,17 +189,19 @@ describe('Exchange core', () => { takerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + RevertReason.OrderUnfillable, ); }); it('should be able to cancel a full order', async () => { await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), }), + RevertReason.OrderUnfillable, ); }); @@ -586,8 +222,9 @@ describe('Exchange core', () => { it('should throw if already cancelled', async () => { await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + RevertReason.OrderUnfillable, ); }); @@ -595,8 +232,9 @@ describe('Exchange core', () => { signedOrder = orderFactory.newSignedOrder({ expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + RevertReason.OrderUnfillable, ); }); @@ -612,10 +250,11 @@ describe('Exchange core', () => { }); const fillTakerAssetAmount2 = new BigNumber(1); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: fillTakerAssetAmount2, }), + RevertReason.RoundingError, ); }); }); @@ -625,16 +264,18 @@ describe('Exchange core', () => { const orderEpoch = new BigNumber(1); await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress); const lesserOrderEpoch = new BigNumber(0); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( 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 expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress), + RevertReason.InvalidNewOrderEpoch, ); }); @@ -705,32 +346,6 @@ describe('Exchange core', () => { }); describe('Testing Exchange of ERC721 Tokens', () => { - it('should successfully exchange a single token between the maker and taker (via fillOrder)', async () => { - // Construct Exchange parameters - const makerAssetId = erc721MakerAssetIds[0]; - const takerAssetId = erc721TakerAssetIds[1]; - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(1), - makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: assetProxyUtils.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; - // tslint:disable-next-line:no-unused-variable - const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - // 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); - }); - it('should throw when maker does not own the token with id makerAssetId', async () => { // Construct Exchange parameters const makerAssetId = erc721TakerAssetIds[0]; @@ -748,8 +363,9 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.TransferFailed, ); }); @@ -770,8 +386,9 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.TransferFailed, ); }); @@ -792,8 +409,9 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.InvalidAmount, ); }); @@ -814,110 +432,52 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.InvalidAmount, ); }); it('should throw on partial fill', async () => { // Construct Exchange parameters const makerAssetId = erc721MakerAssetIds[0]; - const takerAssetId = erc721TakerAssetIds[0]; - signedOrder = orderFactory.newSignedOrder({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(0), - makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: assetProxyUtils.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 expectRevertOrAlwaysFailingTransactionAsync( - exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), - ); - }); - - it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => { - // Construct Exchange parameters - const makerAssetId = erc721MakerAssetIds[0]; signedOrder = orderFactory.newSignedOrder({ makerAssetAmount: new BigNumber(1), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress), }); - // Verify pre-conditions - const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId); - expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress); // Call Exchange - erc20Balances = await erc20Wrapper.getBalancesAsync(); - const takerAssetFillAmount = signedOrder.takerAssetAmount; - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - // Verify ERC721 token was transferred from Maker to Taker - const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId); - expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress); - // Verify ERC20 tokens were transferred from Taker to Maker & fees were paid correctly - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(signedOrder.makerFee), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].minus(signedOrder.takerFee), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add( - signedOrder.makerFee.add(signedOrder.takerFee), - ), + const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); + return expectRevertReasonOrAlwaysFailingTransactionAsync( + exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.RoundingError, ); }); - it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => { + it('should throw if assetData has a length < 132', async () => { // Construct Exchange parameters + const makerAssetId = erc721MakerAssetIds[0]; const takerAssetId = erc721TakerAssetIds[0]; + const makerAssetData = assetProxyUtils + .encodeERC721AssetData(erc721Token.address, makerAssetId) + .slice(0, -2); signedOrder = orderFactory.newSignedOrder({ + makerAssetAmount: new BigNumber(1), takerAssetAmount: new BigNumber(1), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), + makerAssetData, takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId), - makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress), }); // 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 - erc20Balances = await erc20Wrapper.getBalancesAsync(); const takerAssetFillAmount = signedOrder.takerAssetAmount; - await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - // Verify ERC721 token was transferred from Taker to Maker - const newOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId); - expect(newOwnerTakerAsset).to.be.bignumber.equal(makerAddress); - // Verify ERC20 tokens were transferred from Maker to Taker & fees were paid correctly - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].add(signedOrder.makerAssetAmount), - ); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(signedOrder.makerAssetAmount), - ); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(signedOrder.makerFee), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].minus(signedOrder.takerFee), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add( - signedOrder.makerFee.add(signedOrder.takerFee), - ), + return expectRevertReasonOrAlwaysFailingTransactionAsync( + exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + RevertReason.LengthGreaterThan131Required, ); }); }); diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts index abbfd7ac7..afbf958d9 100644 --- a/packages/contracts/test/exchange/dispatcher.ts +++ b/packages/contracts/test/exchange/dispatcher.ts @@ -1,25 +1,31 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetProxyUtils } from '@0xproject/order-utils'; -import { AssetProxyId } from '@0xproject/types'; +import { AssetProxyId, RevertReason } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; - -import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token'; -import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; -import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy'; -import { TestAssetProxyDispatcherContract } from '../../src/generated_contract_wrappers/test_asset_proxy_dispatcher'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; -import { ERC721Wrapper } from '../../src/utils/erc721_wrapper'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import { LogWithDecodedArgs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; +import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_proxy'; +import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; +import { + AssetProxyRegisteredContractEventArgs, + TestAssetProxyDispatcherContract, +} from '../../generated_contract_wrappers/test_asset_proxy_dispatcher'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { LogDecoder } from '../utils/log_decoder'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_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; @@ -43,12 +49,13 @@ describe('AssetProxyDispatcher', () => { before(async () => { // Setup accounts & addresses const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = accounts); + const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = _.slice(accounts, 0, 4)); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); + const numDummyErc20ToDeploy = 1; + [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS); erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); @@ -80,14 +87,8 @@ describe('AssetProxyDispatcher', () => { }); describe('registerAssetProxy', () => { it('should record proxy upon registration', async () => { - const prevProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), + await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); @@ -96,46 +97,30 @@ describe('AssetProxyDispatcher', () => { it('should be able to record multiple proxies', async () => { // Record first proxy - const prevERC20ProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevERC20ProxyAddress, - { from: owner }, - ), + 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 - const prevERC721ProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC721, - erc721Proxy.address, - prevERC721ProxyAddress, - { from: owner }, - ), + 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 replace proxy address upon re-registration', async () => { + it('should throw if a proxy with the same id is already registered', async () => { // Initial registration - const prevProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), + await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - let proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); + 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( @@ -144,111 +129,37 @@ describe('AssetProxyDispatcher', () => { txDefaults, ); // Register new ERC20 Transfer Proxy contract - const newAddress = newErc20TransferProxy.address; - const currentAddress = erc20Proxy.address; - await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - newAddress, - currentAddress, - { from: owner }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify new asset proxy has replaced initial version - proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); - expect(proxyAddress).to.be.equal(newAddress); - }); - - it('should throw if registering with incorrect "currentAssetProxyAddress" field', async () => { - // Initial registration - const prevProxyAddress = constants.NULL_ADDRESS; - await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - // The following transaction will throw because the currentAddress is no longer constants.NULL_ADDRESS - return expectRevertOrAlwaysFailingTransactionAsync( - assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - constants.NULL_ADDRESS, - { from: owner }, - ), - ); - }); - - it('should be able to reset proxy address to NULL', async () => { - // Initial registration - const prevProxyAddress = constants.NULL_ADDRESS; - await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - // The following transaction will reset the proxy address - const newProxyAddress = constants.NULL_ADDRESS; - await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - newProxyAddress, - erc20Proxy.address, - { from: owner }, - ), - constants.AWAIT_TRANSACTION_MINED_MS, + return expectRevertReasonOrAlwaysFailingTransactionAsync( + assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, { + from: owner, + }), + RevertReason.AssetProxyAlreadyExists, ); - const finalProxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); - expect(finalProxyAddress).to.be.equal(newProxyAddress); }); it('should throw if requesting address is not owner', async () => { - const prevProxyAddress = constants.NULL_ADDRESS; - return expectRevertOrAlwaysFailingTransactionAsync( - assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: notOwner }, - ), + return expectRevertReasonOrAlwaysFailingTransactionAsync( + assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }), + RevertReason.OnlyContractOwner, ); }); - it('should throw if attempting to register a proxy to the incorrect id', async () => { - const prevProxyAddress = constants.NULL_ADDRESS; - return expectRevertOrAlwaysFailingTransactionAsync( - assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC721, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), + it('should log an event with correct arguments when an asset proxy is registered', async () => { + const logDecoder = new LogDecoder(web3Wrapper, assetProxyDispatcher.address); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), ); + const logs = txReceipt.logs; + const log = logs[0] as LogWithDecodedArgs<AssetProxyRegisteredContractEventArgs>; + 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 () => { - const prevProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), + await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20); @@ -264,26 +175,19 @@ describe('AssetProxyDispatcher', () => { describe('dispatchTransferFrom', () => { it('should dispatch transfer to registered proxy', async () => { // Register ERC20 proxy - const prevProxyAddress = constants.NULL_ADDRESS; await web3Wrapper.awaitTransactionSuccessAsync( - await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( - AssetProxyId.ERC20, - erc20Proxy.address, - prevProxyAddress, - { from: owner }, - ), + await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); // Construct metadata for ERC20 proxy const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address); - const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2); + // Perform a transfer from makerAddress to takerAddress const erc20Balances = await erc20Wrapper.getBalancesAsync(); const amount = new BigNumber(10); await web3Wrapper.awaitTransactionSuccessAsync( await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync( - encodedAssetDataWithoutProxyId, - AssetProxyId.ERC20, + encodedAssetData, makerAddress, takerAddress, amount, @@ -304,19 +208,19 @@ describe('AssetProxyDispatcher', () => { it('should throw if dispatching to unregistered proxy', async () => { // Construct metadata for ERC20 proxy const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address); - const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(10); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync( - encodedAssetDataWithoutProxyId, - AssetProxyId.ERC20, + encodedAssetData, makerAddress, takerAddress, amount, { from: owner }, ), + RevertReason.AssetProxyDoesNotExist, ); }); }); }); +// tslint:enable:no-unnecessary-type-assertion diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts new file mode 100644 index 000000000..22eb401d9 --- /dev/null +++ b/packages/contracts/test/exchange/fill_order.ts @@ -0,0 +1,305 @@ +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import * as _ from 'lodash'; + +import { chaiSetup } from '../utils/chai_setup'; +import { CoreCombinatorialUtils, coreCombinatorialUtilsFactoryAsync } from '../utils/core_combinatorial_utils'; +import { + AllowanceAmountScenario, + AssetDataScenario, + BalanceAmountScenario, + ExpirationTimeSecondsScenario, + FeeRecipientAddressScenario, + FillScenario, + OrderAssetAmountScenario, + TakerAssetFillAmountScenario, + TakerScenario, +} from '../utils/types'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; + +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 coreCombinatorialUtils: CoreCombinatorialUtils; + + before(async () => { + await blockchainLifecycle.startAsync(); + coreCombinatorialUtils = await coreCombinatorialUtilsFactoryAsync(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 orderScenario = fillScenario.orderScenario; + const description = `Combinatorial OrderFill: ${orderScenario.feeRecipientScenario} ${ + orderScenario.makerAssetAmountScenario + } ${orderScenario.takerAssetAmountScenario} ${orderScenario.makerFeeScenario} ${ + orderScenario.takerFeeScenario + } ${orderScenario.expirationTimeSecondsScenario} ${orderScenario.makerAssetDataScenario} ${ + orderScenario.takerAssetDataScenario + }`; + it(description, async () => { + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + }); + }; + + const allFillScenarios = CoreCombinatorialUtils.generateFillOrderCombinations(); + describe('Combinatorially generated fills orders', () => test(allFillScenarios)); + + it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => { + const fillScenario = { + ...defaultFillScenario, + }; + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + takerAssetAmountScenario: OrderAssetAmountScenario.Small, + }, + }; + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + makerAssetAmountScenario: OrderAssetAmountScenario.Small, + }, + }; + await coreCombinatorialUtils.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 coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => { + const fillScenario = { + ...defaultFillScenario, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount, + }; + await coreCombinatorialUtils.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 coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + + it('should throw if makerAssetAmount is 0', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + makerAssetAmountScenario: OrderAssetAmountScenario.Zero, + }, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount, + }; + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + + it('should throw if takerAssetAmount is 0', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + takerAssetAmountScenario: OrderAssetAmountScenario.Zero, + }, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount, + }; + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + + it('should throw if takerAssetFillAmount is 0', async () => { + const fillScenario = { + ...defaultFillScenario, + takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero, + }; + await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + + it('should throw if an order is expired', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast, + }, + }; + await coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.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 coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); + }); +}); diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts index c08001198..6ded6329c 100644 --- a/packages/contracts/test/exchange/libs.ts +++ b/packages/contracts/test/exchange/libs.ts @@ -4,13 +4,13 @@ import { SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; -import { TestLibsContract } from '../../src/generated_contract_wrappers/test_libs'; -import { addressUtils } from '../../src/utils/address_utils'; -import { artifacts } from '../../src/utils/artifacts'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import { TestLibsContract } from '../../generated_contract_wrappers/test_libs'; +import { addressUtils } from '../utils/address_utils'; +import { artifacts } from '../utils/artifacts'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { OrderFactory } from '../utils/order_factory'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index b8dca04fd..0d07d156f 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -1,27 +1,27 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetProxyUtils } from '@0xproject/order-utils'; -import { AssetProxyId } from '@0xproject/types'; +import { RevertReason } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; -import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token'; -import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token'; -import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; -import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy'; -import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; -import { ERC721Wrapper } from '../../src/utils/erc721_wrapper'; -import { ExchangeWrapper } from '../../src/utils/exchange_wrapper'; -import { MatchOrderTester } from '../../src/utils/match_order_tester'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../../src/utils/types'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; +import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c721_token'; +import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_proxy'; +import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; +import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; +import { MatchOrderTester } from '../utils/match_order_tester'; +import { OrderFactory } from '../utils/order_factory'; +import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../utils/types'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -76,12 +76,16 @@ describe('matchOrders', () => { takerAddress, feeRecipientAddressLeft, feeRecipientAddressRight, - ] = accounts); + ] = _.slice(accounts, 0, 6)); // Create wrappers erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); // Deploy ERC20 token & ERC20 proxy - [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); + 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 @@ -96,11 +100,11 @@ describe('matchOrders', () => { artifacts.Exchange, provider, txDefaults, - zrxToken.address, + assetProxyUtils.encodeERC20AssetData(zrxToken.address), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, owner); + 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, { @@ -598,8 +602,9 @@ describe('matchOrders', () => { // Cancel left order await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + RevertReason.OrderUnfillable, ); }); @@ -622,8 +627,9 @@ describe('matchOrders', () => { // Cancel right order await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + RevertReason.OrderUnfillable, ); }); @@ -644,14 +650,9 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( - matchOrderTester.matchOrdersAndVerifyBalancesAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - ), + return expectRevertReasonOrAlwaysFailingTransactionAsync( + exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + RevertReason.NegativeSpreadRequired, ); }); @@ -672,14 +673,13 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( - matchOrderTester.matchOrdersAndVerifyBalancesAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - ), + return expectRevertReasonOrAlwaysFailingTransactionAsync( + 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, ); }); @@ -702,14 +702,9 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( - matchOrderTester.matchOrdersAndVerifyBalancesAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - ), + return expectRevertReasonOrAlwaysFailingTransactionAsync( + exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + RevertReason.InvalidOrderSignature, ); }); diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 8e221e3f1..1db7dfc6d 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -1,6 +1,6 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { addSignedMessagePrefix, assetProxyUtils, MessagePrefixType, orderHashUtils } from '@0xproject/order-utils'; -import { SignatureType, SignedOrder } from '@0xproject/types'; +import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import ethUtil = require('ethereumjs-util'); @@ -8,17 +8,17 @@ import ethUtil = require('ethereumjs-util'); import { SignatureValidatorApprovalContractEventArgs, TestSignatureValidatorContract, -} from '../../src/generated_contract_wrappers/test_signature_validator'; -import { TestValidatorContract } from '../../src/generated_contract_wrappers/test_validator'; -import { TestWalletContract } from '../../src/generated_contract_wrappers/test_wallet'; -import { addressUtils } from '../../src/utils/address_utils'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrOtherErrorAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { LogDecoder } from '../../src/utils/log_decoder'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +} from '../../generated_contract_wrappers/test_signature_validator'; +import { TestValidatorContract } from '../../generated_contract_wrappers/test_validator'; +import { TestWalletContract } from '../../generated_contract_wrappers/test_wallet'; +import { addressUtils } from '../utils/address_utils'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertOrOtherErrorAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { LogDecoder } from '../utils/log_decoder'; +import { OrderFactory } from '../utils/order_factory'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -107,7 +107,7 @@ describe('MixinSignatureValidator', () => { signedOrder.makerAddress, emptySignature, ), - constants.EXCHANGE_LENGTH_GREATER_THAN_0_REQUIRED, + RevertReason.LengthGreaterThan0Required, ); }); @@ -121,7 +121,7 @@ describe('MixinSignatureValidator', () => { signedOrder.makerAddress, unsupportedSignatureHex, ), - constants.EXCHANGE_SIGNATURE_UNSUPPORTED, + RevertReason.SignatureUnsupported, ); }); @@ -134,7 +134,7 @@ describe('MixinSignatureValidator', () => { signedOrder.makerAddress, unsupportedSignatureHex, ), - constants.EXCHANGE_SIGNATURE_ILLEGAL, + RevertReason.SignatureIllegal, ); }); @@ -161,7 +161,7 @@ describe('MixinSignatureValidator', () => { signedOrder.makerAddress, signatureHex, ), - constants.EXCHANGE_LENGTH_0_REQUIRED, + RevertReason.Length0Required, ); }); diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts index 9a625880c..4f8b49e0e 100644 --- a/packages/contracts/test/exchange/transactions.ts +++ b/packages/contracts/test/exchange/transactions.ts @@ -1,25 +1,26 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils'; -import { AssetProxyId, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types'; +import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; - -import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token'; -import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; -import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange'; -import { ExchangeWrapperContract } from '../../src/generated_contract_wrappers/exchange_wrapper'; -import { WhitelistContract } from '../../src/generated_contract_wrappers/whitelist'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; -import { ExchangeWrapper } from '../../src/utils/exchange_wrapper'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { orderUtils } from '../../src/utils/order_utils'; -import { TransactionFactory } from '../../src/utils/transaction_factory'; -import { ERC20BalancesByOwner, SignedTransaction } from '../../src/utils/types'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import * as _ from 'lodash'; + +import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; +import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_proxy'; +import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { ExchangeWrapperContract } from '../../generated_contract_wrappers/exchange_wrapper'; +import { WhitelistContract } from '../../generated_contract_wrappers/whitelist'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; +import { OrderFactory } from '../utils/order_factory'; +import { orderUtils } from '../utils/order_utils'; +import { TransactionFactory } from '../utils/transaction_factory'; +import { ERC20BalancesByOwner, SignedTransaction } from '../utils/types'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -59,13 +60,27 @@ describe('Exchange transactions', () => { 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] = accounts); + const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = _.slice( + accounts, + 0, + 5, + )); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); + const numDummyErc20ToDeploy = 3; + [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); @@ -73,10 +88,10 @@ describe('Exchange transactions', () => { artifacts.Exchange, provider, txDefaults, - zrxToken.address, + assetProxyUtils.encodeERC20AssetData(zrxToken.address), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); await web3Wrapper.awaitTransactionSuccessAsync( await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }), @@ -101,13 +116,6 @@ describe('Exchange transactions', () => { makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address); takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address); }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('executeTransaction', () => { describe('fillOrder', () => { let takerAssetFillAmount: BigNumber; @@ -126,8 +134,9 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.executeTransactionAsync(signedTx, takerAddress), + RevertReason.FailedExecution, ); }); @@ -168,8 +177,9 @@ describe('Exchange transactions', () => { it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => { await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.executeTransactionAsync(signedTx, senderAddress), + RevertReason.InvalidTxHash, ); }); @@ -187,15 +197,17 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( 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 expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, senderAddress), + RevertReason.OrderUnfillable, ); }); }); @@ -238,7 +250,7 @@ describe('Exchange transactions', () => { signedOrder.signature, ); const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapperContract.fillOrder.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -247,6 +259,7 @@ describe('Exchange transactions', () => { signedFillTx.signature, { from: takerAddress }, ), + RevertReason.FailedExecution, ); }); @@ -357,7 +370,7 @@ describe('Exchange transactions', () => { orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); const takerAssetFillAmount = signedOrder.takerAssetAmount; const salt = generatePseudoRandomSalt(); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -365,6 +378,7 @@ describe('Exchange transactions', () => { signedOrder.signature, { from: takerAddress }, ), + RevertReason.MakerNotWhitelisted, ); }); @@ -378,7 +392,7 @@ describe('Exchange transactions', () => { orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); const takerAssetFillAmount = signedOrder.takerAssetAmount; const salt = generatePseudoRandomSalt(); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -386,6 +400,7 @@ describe('Exchange transactions', () => { signedOrder.signature, { from: takerAddress }, ), + RevertReason.TakerNotWhitelisted, ); }); diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts index 703f644b8..7942f7695 100644 --- a/packages/contracts/test/exchange/wrapper.ts +++ b/packages/contracts/test/exchange/wrapper.ts @@ -1,26 +1,26 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetProxyUtils } from '@0xproject/order-utils'; -import { AssetProxyId, SignedOrder } from '@0xproject/types'; +import { RevertReason, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; -import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token'; -import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token'; -import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; -import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy'; -import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange'; -import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; -import { chaiSetup } from '../../src/utils/chai_setup'; -import { constants } from '../../src/utils/constants'; -import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; -import { ERC721Wrapper } from '../../src/utils/erc721_wrapper'; -import { ExchangeWrapper } from '../../src/utils/exchange_wrapper'; -import { OrderFactory } from '../../src/utils/order_factory'; -import { ERC20BalancesByOwner } from '../../src/utils/types'; -import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; +import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; +import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c721_token'; +import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_proxy'; +import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; +import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { artifacts } from '../utils/artifacts'; +import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { chaiSetup } from '../utils/chai_setup'; +import { constants } from '../utils/constants'; +import { ERC20Wrapper } from '../utils/erc20_wrapper'; +import { ERC721Wrapper } from '../utils/erc721_wrapper'; +import { ExchangeWrapper } from '../utils/exchange_wrapper'; +import { OrderFactory } from '../utils/order_factory'; +import { ERC20BalancesByOwner } from '../utils/types'; +import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; @@ -60,12 +60,16 @@ describe('Exchange wrappers', () => { }); before(async () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); + const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4)); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); + const numDummyErc20ToDeploy = 3; + [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); @@ -80,11 +84,11 @@ describe('Exchange wrappers', () => { artifacts.Exchange, provider, txDefaults, - zrxToken.address, + assetProxyUtils.encodeERC20AssetData(zrxToken.address), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); await web3Wrapper.awaitTransactionSuccessAsync( await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { @@ -165,13 +169,14 @@ describe('Exchange wrappers', () => { ); }); - it('should throw if an signedOrder is expired', async () => { + it('should throw if a signedOrder is expired', async () => { const signedOrder = orderFactory.newSignedOrder({ expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), + RevertReason.OrderUnfillable, ); }); @@ -182,8 +187,9 @@ describe('Exchange wrappers', () => { takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), + RevertReason.CompleteFillFailed, ); }); }); @@ -368,7 +374,7 @@ describe('Exchange wrappers', () => { // 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: 270000, + gas: 280000, }); // Verify post-conditions const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId); @@ -494,10 +500,11 @@ describe('Exchange wrappers', () => { await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts, }), + RevertReason.OrderUnfillable, ); }); }); @@ -687,7 +694,7 @@ describe('Exchange wrappers', () => { expect(newBalances).to.be.deep.equal(erc20Balances); }); - it('should throw when an signedOrder does not use the same takerAssetAddress', async () => { + it('should throw when a signedOrder does not use the same takerAssetAddress', async () => { signedOrders = [ orderFactory.newSignedOrder(), orderFactory.newSignedOrder({ @@ -696,10 +703,13 @@ describe('Exchange wrappers', () => { orderFactory.newSignedOrder(), ]; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( 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, ); }); }); @@ -902,7 +912,7 @@ describe('Exchange wrappers', () => { expect(newBalances).to.be.deep.equal(erc20Balances); }); - it('should throw when an signedOrder does not use the same makerAssetAddress', async () => { + it('should throw when a signedOrder does not use the same makerAssetAddress', async () => { signedOrders = [ orderFactory.newSignedOrder(), orderFactory.newSignedOrder({ @@ -911,10 +921,11 @@ describe('Exchange wrappers', () => { orderFactory.newSignedOrder(), ]; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, { makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), }), + RevertReason.InvalidOrderSignature, ); }); }); |