diff options
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | packages/contracts/src/contracts/current/test/Whitelist/Whitelist.sol | 10 | ||||
-rw-r--r-- | packages/contracts/src/contracts/current/utils/Ownable/Ownable.sol | 2 | ||||
-rw-r--r-- | packages/contracts/src/utils/assertions.ts | 12 | ||||
-rw-r--r-- | packages/contracts/src/utils/types.ts | 35 | ||||
-rw-r--r-- | packages/contracts/test/asset_proxy/authorizable.ts | 17 | ||||
-rw-r--r-- | packages/contracts/test/asset_proxy/proxies.ts | 34 | ||||
-rw-r--r-- | packages/contracts/test/exchange/core.ts | 88 | ||||
-rw-r--r-- | packages/contracts/test/exchange/dispatcher.ts | 15 | ||||
-rw-r--r-- | packages/contracts/test/exchange/match_orders.ts | 25 | ||||
-rw-r--r-- | packages/contracts/test/exchange/transactions.ts | 40 | ||||
-rw-r--r-- | packages/contracts/test/exchange/wrapper.ts | 29 |
12 files changed, 215 insertions, 93 deletions
diff --git a/package.json b/package.json index 11444d16d..3436f152b 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "build": "wsrun build $PKG --fast-exit -r --stages", "build:monorepo_scripts": "PKG=@0xproject/monorepo-scripts yarn build", "clean": "wsrun clean $PKG --fast-exit -r --parallel", + "remove_node_modules": "lerna clean --yes; rm -rf node_modules", "rebuild": "run-s clean build", "test": "wsrun test $PKG --fast-exit --serial --exclude-missing", "stage_docs": "wsrun docs:stage $PKG --fast-exit --parallel --exclude-missing", diff --git a/packages/contracts/src/contracts/current/test/Whitelist/Whitelist.sol b/packages/contracts/src/contracts/current/test/Whitelist/Whitelist.sol index d35815474..8b52858b1 100644 --- a/packages/contracts/src/contracts/current/test/Whitelist/Whitelist.sol +++ b/packages/contracts/src/contracts/current/test/Whitelist/Whitelist.sol @@ -23,13 +23,13 @@ import "../../protocol/Exchange/interfaces/IExchange.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; import "../../utils/Ownable/Ownable.sol"; -contract Whitelist is +contract Whitelist is Ownable { // Revert reasons - string constant MAKER_NOT_WHITELISTED = "Maker address not whitelisted."; - string constant TAKER_NOT_WHITELISTED = "Taker address not whitelisted."; - string constant INVALID_SENDER = "Sender must equal transaction origin."; + string constant MAKER_NOT_WHITELISTED = "MAKER_NOT_WHITELISTED"; // Maker address not whitelisted. + string constant TAKER_NOT_WHITELISTED = "TAKER_NOT_WHITELISTED"; // Taker address not whitelisted. + string constant INVALID_SENDER = "INVALID_SENDER"; // Sender must equal transaction origin. // Mapping of address => whitelist status. mapping (address => bool) public isWhitelisted; @@ -77,7 +77,7 @@ contract Whitelist is public { address takerAddress = msg.sender; - + // This contract must be the entry point for the transaction. require( takerAddress == tx.origin, diff --git a/packages/contracts/src/contracts/current/utils/Ownable/Ownable.sol b/packages/contracts/src/contracts/current/utils/Ownable/Ownable.sol index 296c6c856..048fdb46f 100644 --- a/packages/contracts/src/contracts/current/utils/Ownable/Ownable.sol +++ b/packages/contracts/src/contracts/current/utils/Ownable/Ownable.sol @@ -22,7 +22,7 @@ contract Ownable is IOwnable { modifier onlyOwner() { require( msg.sender == owner, - "Only contract owner is allowed to call this method." + 'ONLY_CONTRACT_OWNER' ); _; } diff --git a/packages/contracts/src/utils/assertions.ts b/packages/contracts/src/utils/assertions.ts index 615e648f3..29489e648 100644 --- a/packages/contracts/src/utils/assertions.ts +++ b/packages/contracts/src/utils/assertions.ts @@ -52,6 +52,18 @@ export function expectRevertOrAlwaysFailingTransactionAsync<T>(p: Promise<T>): P } /** + * Rejects if the given Promise does not reject with the given revert reason or "always + * failing transaction" error. + * @param p the Promise which is expected to reject + * @param reason a specific revert reason + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export function expectRevertReasonOrAlwaysFailingTransactionAsync<T>(p: Promise<T>, reason: string): PromiseLike<void> { + return _expectEitherErrorAsync(p, 'always failing transaction', reason); +} + +/** * Rejects if the given Promise does not reject with a "revert" or "Contract * call failed" error. * @param p the Promise which is expected to reject diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 7a1f92afd..c1eb72099 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -151,3 +151,38 @@ export interface MatchOrder { leftSignature: string; rightSignature: string; } + +export enum ContractLibErrors { + OrderUnfillable = 'ORDER_UNFILLABLE', + InvalidMaker = 'INVALID_MAKER', + InvalidTaker = 'INVALID_TAKER', + InvalidSender = 'INVALID_SENDER', + InvalidOrderSignature = 'INVALID_ORDER_SIGNATURE', + InvalidTakerAmount = 'INVALID_TAKER_AMOUNT', + RoundingError = 'ROUNDING_ERROR', + InvalidSignature = 'INVALID_SIGNATURE', + SignatureIllegal = 'SIGNATURE_ILLEGAL', + SignatureUnsupported = 'SIGNATURE_UNSUPPORTED', + InvalidNewOrderEpoch = 'INVALID_NEW_ORDER_EPOCH', + CompleteFillFailed = 'COMPLETE_FILL_FAILED', + NegativeSpreadRequired = 'NEGATIVE_SPREAD_REQUIRED', + ReentrancyIllegal = 'REENTRANCY_ILLEGAL', + InvalidTxHash = 'INVALID_TX_HASH', + InvalidTxSignature = 'INVALID_TX_SIGNATURE', + FailedExecution = 'FAILED_EXECUTION', + AssetProxyMismatch = 'ASSET_PROXY_MISMATCH', + AssetProxyIdMismatch = 'ASSET_PROXY_ID_MISMATCH', + LengthGreaterThan0Required = 'LENGTH_GREATER_THAN_0_REQUIRED', + Length1Required = 'LENGTH_1_REQUIRED', + Length66Required = 'LENGTH_66_REQUIRED', + InvalidAmount = 'INVALID_AMOUNT', + TransferFailed = 'TRANSFER_FAILED', + SenderNotAuthorized = 'SENDER_NOT_AUTHORIZED', + TargetNotAuthorized = 'TARGET_NOT_AUTHORIZED', + TargetAlreadyAuthorized = 'TARGET_ALREADY_AUTHORIZED', + IndexOutOfBounds = 'INDEX_OUT_OF_BOUNDS', + AuthorizedAddressMismatch = 'AUTHORIZED_ADDRESS_MISMATCH', + OnlyContractOwner = 'ONLY_CONTRACT_OWNER', + MakerNotWhitelisted = 'MAKER_NOT_WHITELISTED', + TakerNotWhitelisted = 'TAKER_NOT_WHITELISTED', +} diff --git a/packages/contracts/test/asset_proxy/authorizable.ts b/packages/contracts/test/asset_proxy/authorizable.ts index ed582b63e..1ebb094a1 100644 --- a/packages/contracts/test/asset_proxy/authorizable.ts +++ b/packages/contracts/test/asset_proxy/authorizable.ts @@ -3,9 +3,12 @@ import * as chai from 'chai'; import { MixinAuthorizableContract } from '../../src/generated_contract_wrappers/mixin_authorizable'; import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; +import { + expectRevertReasonOrAlwaysFailingTransactionAsync, +} from '../../src/utils/assertions'; import { chaiSetup } from '../../src/utils/chai_setup'; import { constants } from '../../src/utils/constants'; +import { ContractLibErrors } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -42,8 +45,9 @@ describe('Authorizable', () => { }); describe('addAuthorizedAddress', () => { it('should throw if not called by owner', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }), + ContractLibErrors.OnlyContractOwner, ); }); it('should allow owner to add an authorized address', async () => { @@ -59,8 +63,9 @@ describe('Authorizable', () => { await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), + ContractLibErrors.TargetAlreadyAuthorized, ); }); }); @@ -71,10 +76,11 @@ describe('Authorizable', () => { await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner, }), + ContractLibErrors.OnlyContractOwner, ); }); @@ -94,10 +100,11 @@ describe('Authorizable', () => { }); it('should throw if owner attempts to remove an address that is not authorized', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: owner, }), + ContractLibErrors.TargetNotAuthorized, ); }); }); diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts index 2c27f7382..2c1f52973 100644 --- a/packages/contracts/test/asset_proxy/proxies.ts +++ b/packages/contracts/test/asset_proxy/proxies.ts @@ -15,12 +15,16 @@ import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/ import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy'; import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy'; import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; +import { + expectRevertOrAlwaysFailingTransactionAsync, + expectRevertReasonOrAlwaysFailingTransactionAsync, +} 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 { LogDecoder } from '../../src/utils/log_decoder'; +import { ContractLibErrors } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -160,14 +164,15 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // Perform a transfer; expect this to fail. - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc20Proxy.transferFrom.sendTransactionAsync( encodedAssetData, makerAddress, takerAddress, transferAmount, - { from: notAuthorized }, + { from: exchangeAddress }, ), + ContractLibErrors.TransferFailed, ); }); @@ -177,7 +182,7 @@ describe('Asset Transfer Proxies', () => { const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(10); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc20Proxy.transferFrom.sendTransactionAsync( encodedAssetDataWithoutProxyId, makerAddress, @@ -187,6 +192,7 @@ describe('Asset Transfer Proxies', () => { from: notAuthorized, }, ), + ContractLibErrors.SenderNotAuthorized, ); }); }); @@ -236,10 +242,11 @@ describe('Asset Transfer Proxies', () => { const toAddresses = _.times(numTransfers, () => takerAddress); const amounts = _.times(numTransfers, () => amount); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc20Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, { from: notAuthorized, }), + ContractLibErrors.SenderNotAuthorized, ); }); }); @@ -377,7 +384,7 @@ describe('Asset Transfer Proxies', () => { expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(0); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc721Proxy.transferFrom.sendTransactionAsync( encodedAssetDataWithoutProxyId, makerAddress, @@ -385,6 +392,7 @@ describe('Asset Transfer Proxies', () => { amount, { from: exchangeAddress }, ), + ContractLibErrors.InvalidAmount, ); }); @@ -397,7 +405,7 @@ describe('Asset Transfer Proxies', () => { expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(500); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc721Proxy.transferFrom.sendTransactionAsync( encodedAssetDataWithoutProxyId, makerAddress, @@ -405,6 +413,7 @@ describe('Asset Transfer Proxies', () => { amount, { from: exchangeAddress }, ), + ContractLibErrors.InvalidAmount, ); }); @@ -421,16 +430,17 @@ describe('Asset Transfer Proxies', () => { ); // Perform a transfer; expect this to fail. const amount = new BigNumber(1); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc20Proxy.transferFrom.sendTransactionAsync( encodedAssetDataWithoutProxyId, makerAddress, takerAddress, amount, { - from: notAuthorized, + from: exchangeAddress, }, ), + ContractLibErrors.TransferFailed, ); }); @@ -440,7 +450,7 @@ describe('Asset Transfer Proxies', () => { const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(1); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc721Proxy.transferFrom.sendTransactionAsync( encodedAssetDataWithoutProxyId, makerAddress, @@ -448,6 +458,7 @@ describe('Asset Transfer Proxies', () => { amount, { from: notAuthorized }, ), + ContractLibErrors.SenderNotAuthorized, ); }); }); @@ -498,10 +509,11 @@ describe('Asset Transfer Proxies', () => { const toAddresses = _.times(numTransfers, () => takerAddress); const amounts = _.times(numTransfers, () => new BigNumber(1)); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( erc721Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, { from: notAuthorized, }), + ContractLibErrors.SenderNotAuthorized, ); }); }); diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index ff652d3aa..d35ff7dee 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -17,14 +17,17 @@ import { FillContractEventArgs, } from '../../src/generated_contract_wrappers/exchange'; import { artifacts } from '../../src/utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; +import { + expectRevertOrAlwaysFailingTransactionAsync, + expectRevertReasonOrAlwaysFailingTransactionAsync, +} 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 { ContractLibErrors, ERC20BalancesByOwner } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -415,8 +418,9 @@ describe('Exchange core', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.InvalidTaker, ); }); @@ -432,8 +436,9 @@ describe('Exchange core', () => { const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]); const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`; signedOrder.signature = invalidSigHex; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.InvalidOrderSignature, ); }); @@ -442,8 +447,9 @@ describe('Exchange core', () => { makerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -452,18 +458,20 @@ describe('Exchange core', () => { takerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.OrderUnfillable, ); }); it('should throw if takerAssetFillAmount is 0', async () => { signedOrder = orderFactory.newSignedOrder(); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: new BigNumber(0), }), + ContractLibErrors.InvalidTakerAmount, ); }); @@ -472,8 +480,9 @@ describe('Exchange core', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.TransferFailed, ); }); @@ -481,8 +490,9 @@ describe('Exchange core', () => { signedOrder = orderFactory.newSignedOrder({ takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.TransferFailed, ); }); @@ -493,8 +503,9 @@ describe('Exchange core', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.TransferFailed, ); }); @@ -505,8 +516,9 @@ describe('Exchange core', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.TransferFailed, ); }); @@ -514,16 +526,18 @@ describe('Exchange core', () => { signedOrder = orderFactory.newSignedOrder({ expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.OrderUnfillable, ); }); 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), + ContractLibErrors.OrderUnfillable, ); }); }); @@ -535,8 +549,9 @@ describe('Exchange core', () => { }); it('should throw if not sent by maker', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress), + ContractLibErrors.InvalidMaker, ); }); @@ -545,8 +560,9 @@ describe('Exchange core', () => { makerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -555,17 +571,19 @@ describe('Exchange core', () => { takerAssetAmount: new BigNumber(0), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + ContractLibErrors.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), }), + ContractLibErrors.OrderUnfillable, ); }); @@ -586,8 +604,9 @@ describe('Exchange core', () => { it('should throw if already cancelled', async () => { await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -595,8 +614,9 @@ describe('Exchange core', () => { signedOrder = orderFactory.newSignedOrder({ expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -612,10 +632,11 @@ describe('Exchange core', () => { }); const fillTakerAssetAmount2 = new BigNumber(1); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: fillTakerAssetAmount2, }), + ContractLibErrors.RoundingError, ); }); }); @@ -625,16 +646,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), + ContractLibErrors.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), + ContractLibErrors.InvalidNewOrderEpoch, ); }); @@ -792,8 +815,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 }), + ContractLibErrors.InvalidAmount, ); }); @@ -814,30 +838,26 @@ 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 }), + ContractLibErrors.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), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId), + takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress), }); - // 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( + const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), + ContractLibErrors.RoundingError, ); }); diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts index abbfd7ac7..299950603 100644 --- a/packages/contracts/test/exchange/dispatcher.ts +++ b/packages/contracts/test/exchange/dispatcher.ts @@ -9,11 +9,15 @@ import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c2 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 { + expectRevertOrAlwaysFailingTransactionAsync, + expectRevertReasonOrAlwaysFailingTransactionAsync, +} 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 { ContractLibErrors } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -175,13 +179,14 @@ describe('AssetProxyDispatcher', () => { 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( + return expectRevertReasonOrAlwaysFailingTransactionAsync( assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( AssetProxyId.ERC20, erc20Proxy.address, constants.NULL_ADDRESS, { from: owner }, ), + ContractLibErrors.AssetProxyMismatch, ); }); @@ -216,25 +221,27 @@ describe('AssetProxyDispatcher', () => { it('should throw if requesting address is not owner', async () => { const prevProxyAddress = constants.NULL_ADDRESS; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( AssetProxyId.ERC20, erc20Proxy.address, prevProxyAddress, { from: notOwner }, ), + ContractLibErrors.OnlyContractOwner, ); }); it('should throw if attempting to register a proxy to the incorrect id', async () => { const prevProxyAddress = constants.NULL_ADDRESS; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( AssetProxyId.ERC721, erc20Proxy.address, prevProxyAddress, { from: owner }, ), + ContractLibErrors.AssetProxyIdMismatch, ); }); }); diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index b8dca04fd..9d2378dc8 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -12,7 +12,9 @@ import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c2 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 { + expectRevertReasonOrAlwaysFailingTransactionAsync, +} from '../../src/utils/assertions'; import { chaiSetup } from '../../src/utils/chai_setup'; import { constants } from '../../src/utils/constants'; import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; @@ -20,7 +22,7 @@ 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 { ContractLibErrors, ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -598,8 +600,9 @@ describe('matchOrders', () => { // Cancel left order await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -622,8 +625,9 @@ describe('matchOrders', () => { // Cancel right order await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + ContractLibErrors.OrderUnfillable, ); }); @@ -644,7 +648,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, @@ -652,6 +656,7 @@ describe('matchOrders', () => { erc20BalancesByOwner, erc721TokenIdsByOwner, ), + ContractLibErrors.NegativeSpreadRequired, ); }); @@ -672,7 +677,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, @@ -680,6 +685,11 @@ describe('matchOrders', () => { erc20BalancesByOwner, erc721TokenIdsByOwner, ), + // 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 + ContractLibErrors.InvalidOrderSignature, ); }); @@ -702,7 +712,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, @@ -710,6 +720,7 @@ describe('matchOrders', () => { erc20BalancesByOwner, erc721TokenIdsByOwner, ), + ContractLibErrors.InvalidOrderSignature, ); }); diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts index 9a625880c..958a6dce8 100644 --- a/packages/contracts/test/exchange/transactions.ts +++ b/packages/contracts/test/exchange/transactions.ts @@ -10,7 +10,9 @@ 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 { + expectRevertReasonOrAlwaysFailingTransactionAsync, +} from '../../src/utils/assertions'; import { chaiSetup } from '../../src/utils/chai_setup'; import { constants } from '../../src/utils/constants'; import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; @@ -18,7 +20,7 @@ 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 { ContractLibErrors, ERC20BalancesByOwner, SignedTransaction } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -59,6 +61,12 @@ 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); @@ -101,13 +109,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 +127,9 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.executeTransactionAsync(signedTx, takerAddress), + ContractLibErrors.FailedExecution, ); }); @@ -168,8 +170,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), + ContractLibErrors.InvalidTxHash, ); }); @@ -187,15 +190,17 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.executeTransactionAsync(signedTx, makerAddress), + ContractLibErrors.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), + ContractLibErrors.OrderUnfillable, ); }); }); @@ -238,7 +243,7 @@ describe('Exchange transactions', () => { signedOrder.signature, ); const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapperContract.fillOrder.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -247,6 +252,7 @@ describe('Exchange transactions', () => { signedFillTx.signature, { from: takerAddress }, ), + ContractLibErrors.FailedExecution, ); }); @@ -357,7 +363,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 +371,7 @@ describe('Exchange transactions', () => { signedOrder.signature, { from: takerAddress }, ), + ContractLibErrors.MakerNotWhitelisted, ); }); @@ -378,7 +385,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 +393,7 @@ describe('Exchange transactions', () => { signedOrder.signature, { from: takerAddress }, ), + ContractLibErrors.TakerNotWhitelisted, ); }); diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts index 703f644b8..3d7465659 100644 --- a/packages/contracts/test/exchange/wrapper.ts +++ b/packages/contracts/test/exchange/wrapper.ts @@ -12,14 +12,16 @@ import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c2 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 { + expectRevertReasonOrAlwaysFailingTransactionAsync, +} 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 { ContractLibErrors, ERC20BalancesByOwner } from '../../src/utils/types'; import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'; chaiSetup.configure(); @@ -165,13 +167,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), + ContractLibErrors.OrderUnfillable, ); }); @@ -182,8 +185,9 @@ describe('Exchange wrappers', () => { takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), + ContractLibErrors.CompleteFillFailed, ); }); }); @@ -494,10 +498,11 @@ describe('Exchange wrappers', () => { await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts, }), + ContractLibErrors.OrderUnfillable, ); }); }); @@ -687,7 +692,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 +701,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 + ContractLibErrors.InvalidOrderSignature, ); }); }); @@ -902,7 +910,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 +919,11 @@ describe('Exchange wrappers', () => { orderFactory.newSignedOrder(), ]; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectRevertReasonOrAlwaysFailingTransactionAsync( exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, { makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), }), + ContractLibErrors.InvalidOrderSignature, ); }); }); |