In @0x/contracts-exchange: Update tests for rich reverts

This commit is contained in:
Lawrence Forman 2019-04-05 00:34:24 -04:00 committed by Amir Bandeali
parent 06499f2155
commit 20d8c1b51a
8 changed files with 217 additions and 193 deletions

View File

@ -22,12 +22,14 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
import "../src/MixinSignatureValidator.sol"; import "../src/MixinSignatureValidator.sol";
import "../src/MixinTransactions.sol"; import "../src/MixinTransactions.sol";
import "../src/MixinExchangeRichErrors.sol";
contract TestSignatureValidator is contract TestSignatureValidator is
LibEIP712ExchangeDomain, LibEIP712ExchangeDomain,
MixinSignatureValidator, MixinSignatureValidator,
MixinTransactions MixinTransactions,
MixinExchangeRichErrors
{ {
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks

View File

@ -21,7 +21,6 @@ import {
chaiSetup, chaiSetup,
constants, constants,
ERC20BalancesByOwner, ERC20BalancesByOwner,
expectTransactionFailedAsync,
getLatestBlockTimestampAsync, getLatestBlockTimestampAsync,
increaseTimeAndMineBlockAsync, increaseTimeAndMineBlockAsync,
OrderFactory, OrderFactory,
@ -56,7 +55,6 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
// tslint:disable:no-unnecessary-type-assertion // tslint:disable:no-unnecessary-type-assertion
describe('Exchange core', () => { describe('Exchange core', () => {
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
let chainId: number; let chainId: number;
let makerAddress: string; let makerAddress: string;
let owner: string; let owner: string;
@ -266,7 +264,7 @@ describe('Exchange core', () => {
signedOrder.signature = invalidSigHex; signedOrder.signature = invalidSigHex;
const expectedError = new ExchangeRevertErrors.SignatureError( const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex, orderHashHex,
ExchangeRevertErrors.SignatureErrorCodes.BadSignature, ExchangeRevertErrors.SignatureErrorCode.BadSignature,
); );
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
@ -276,10 +274,7 @@ describe('Exchange core', () => {
signedOrder = await orderFactory.newSignedOrderAsync(); signedOrder = await orderFactory.newSignedOrderAsync();
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHex, OrderStatus.FullyFilled);
orderHashHex,
OrderStatus.FullyFilled,
);
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -303,7 +298,7 @@ describe('Exchange core', () => {
signedOrder.signature = `0x0${SignatureType.Wallet}`; signedOrder.signature = `0x0${SignatureType.Wallet}`;
const expectedError = new ExchangeRevertErrors.SignatureError( const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex, orderHashHex,
ExchangeRevertErrors.SignatureErrorCodes.WalletError, ExchangeRevertErrors.SignatureErrorCode.WalletError,
); );
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
@ -320,7 +315,7 @@ describe('Exchange core', () => {
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.SignatureError( const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex, orderHashHex,
ExchangeRevertErrors.SignatureErrorCodes.ValidatorError, ExchangeRevertErrors.SignatureErrorCode.ValidatorError,
); );
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
@ -497,10 +492,7 @@ describe('Exchange core', () => {
it('should throw if not sent by maker', async () => { it('should throw if not sent by maker', async () => {
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.InvalidMakerError( const expectedError = new ExchangeRevertErrors.InvalidMakerError(orderHash, takerAddress);
orderHash,
takerAddress,
);
const tx = exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress); const tx = exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -534,10 +526,7 @@ describe('Exchange core', () => {
it('should be able to cancel an order', async () => { it('should be able to cancel an order', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Cancelled);
orderHash,
OrderStatus.Cancelled,
);
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
}); });
@ -562,10 +551,7 @@ describe('Exchange core', () => {
it('should throw if already cancelled', async () => { it('should throw if already cancelled', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Cancelled);
orderHash,
OrderStatus.Cancelled,
);
const tx = exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); const tx = exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -576,10 +562,7 @@ describe('Exchange core', () => {
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
}); });
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Expired);
orderHash,
OrderStatus.Expired,
);
const tx = exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); const tx = exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -610,7 +593,7 @@ describe('Exchange core', () => {
const lesserOrderEpoch = new BigNumber(0); const lesserOrderEpoch = new BigNumber(0);
const expectedError = new ExchangeRevertErrors.OrderEpochError( const expectedError = new ExchangeRevertErrors.OrderEpochError(
makerAddress, makerAddress,
ZERO_ADDRESS, constants.NULL_ADDRESS,
orderEpoch.plus(1), orderEpoch.plus(1),
); );
const tx = exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress); const tx = exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress);
@ -622,7 +605,7 @@ describe('Exchange core', () => {
await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress); await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
const expectedError = new ExchangeRevertErrors.OrderEpochError( const expectedError = new ExchangeRevertErrors.OrderEpochError(
makerAddress, makerAddress,
ZERO_ADDRESS, constants.NULL_ADDRESS,
orderEpoch.plus(1), orderEpoch.plus(1),
); );
const tx = exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress); const tx = exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);

View File

@ -9,7 +9,6 @@ import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { import {
chaiSetup, chaiSetup,
constants, constants,
expectTransactionFailedAsync,
LogDecoder, LogDecoder,
orderUtils, orderUtils,
provider, provider,
@ -137,18 +136,16 @@ describe('AssetProxyDispatcher', () => {
txDefaults, txDefaults,
); );
const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(proxyAddress); const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(proxyAddress);
const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
newErc20TransferProxy.address, from: owner,
{ from: owner }, });
);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
it('should throw if requesting address is not owner', async () => { it('should throw if requesting address is not owner', async () => {
const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync( const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
erc20Proxy.address, from: notOwner,
{ from: notOwner }, });
);
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
}); });
@ -279,7 +276,7 @@ describe('AssetProxyDispatcher', () => {
const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError( const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError(
orderHash, orderHash,
encodedAssetData, encodedAssetData,
ExchangeRevertErrors.AssetProxyDispatchErrorCodes.UnknownAssetProxy, ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy,
); );
const tx = assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync( const tx = assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
orderHash, orderHash,

View File

@ -6,7 +6,6 @@ import {
constants, constants,
ERC20BalancesByOwner, ERC20BalancesByOwner,
ERC721TokenIdsByOwner, ERC721TokenIdsByOwner,
expectTransactionFailedAsync,
OrderFactory, OrderFactory,
provider, provider,
txDefaults, txDefaults,
@ -588,10 +587,12 @@ describe('matchOrders', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.matchOrdersAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), signedOrderLeft,
RevertReason.ReentrancyIllegal, signedOrderRight,
takerAddress,
); );
return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
}); });
}); });
}; };
@ -1129,10 +1130,7 @@ describe('matchOrders', () => {
// Cancel left order // Cancel left order
await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress); await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
// Match orders // Match orders
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexLeft, OrderStatus.Cancelled);
orderHashHexLeft,
OrderStatus.Cancelled,
);
const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -1151,10 +1149,7 @@ describe('matchOrders', () => {
// Cancel right order // Cancel right order
await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress); await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
// Match orders // Match orders
const expectedError = new ExchangeRevertErrors.OrderStatusError( const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexRight, OrderStatus.Cancelled);
orderHashHexRight,
OrderStatus.Cancelled,
);
const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -1172,10 +1167,7 @@ describe('matchOrders', () => {
const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft); const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft);
const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight); const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight);
// Match orders // Match orders
const expectedError = new ExchangeRevertErrors.NegativeSpreadError( const expectedError = new ExchangeRevertErrors.NegativeSpreadError(orderHashHexLeft, orderHashHexRight);
orderHashHexLeft,
orderHashHexRight,
);
const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -1202,7 +1194,7 @@ describe('matchOrders', () => {
const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight);
const expectedError = new ExchangeRevertErrors.SignatureError( const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex, orderHashHex,
ExchangeRevertErrors.SignatureErrorCodes.BadSignature, ExchangeRevertErrors.SignatureErrorCode.BadSignature,
); );
// Match orders // Match orders
const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
@ -1227,7 +1219,7 @@ describe('matchOrders', () => {
const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight);
const expectedError = new ExchangeRevertErrors.SignatureError( const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex, orderHashHex,
ExchangeRevertErrors.SignatureErrorCodes.BadSignature, ExchangeRevertErrors.SignatureErrorCode.BadSignature,
); );
// Match orders // Match orders
const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const tx = exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);

View File

@ -2,7 +2,6 @@ import {
addressUtils, addressUtils,
chaiSetup, chaiSetup,
constants, constants,
expectContractCallFailedAsync,
LogDecoder, LogDecoder,
OrderFactory, OrderFactory,
provider, provider,
@ -10,7 +9,12 @@ import {
web3Wrapper, web3Wrapper,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils'; import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; import {
assetDataUtils,
ExchangeRevertErrors,
orderHashUtils,
signatureUtils
} from '@0x/order-utils';
import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
import { BigNumber, providerUtils } from '@0x/utils'; import { BigNumber, providerUtils } from '@0x/utils';
import * as chai from 'chai'; import * as chai from 'chai';
@ -130,41 +134,47 @@ describe('MixinSignatureValidator', () => {
it('should revert when signature is empty', async () => { it('should revert when signature is empty', async () => {
const emptySignature = '0x'; const emptySignature = '0x';
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync( orderHashHex,
orderHashHex, ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
signedOrder.makerAddress,
emptySignature,
),
RevertReason.LengthGreaterThan0Required,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
emptySignature,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should revert when signature type is unsupported', async () => { it('should revert when signature type is unsupported', async () => {
const unsupportedSignatureType = SignatureType.NSignatureTypes; const unsupportedSignatureType = SignatureType.NSignatureTypes;
const unsupportedSignatureHex = `0x${Buffer.from([unsupportedSignatureType]).toString('hex')}`; const unsupportedSignatureHex = `0x${Buffer.from([unsupportedSignatureType]).toString('hex')}`;
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync( orderHashHex,
orderHashHex, ExchangeRevertErrors.SignatureErrorCode.Unsupported,
signedOrder.makerAddress,
unsupportedSignatureHex,
),
RevertReason.SignatureUnsupported,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
unsupportedSignatureHex,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should revert when SignatureType=Illegal', async () => { it('should revert when SignatureType=Illegal', async () => {
const unsupportedSignatureHex = `0x${Buffer.from([SignatureType.Illegal]).toString('hex')}`; const unsupportedSignatureHex = `0x${Buffer.from([SignatureType.Illegal]).toString('hex')}`;
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync( orderHashHex,
orderHashHex, ExchangeRevertErrors.SignatureErrorCode.Illegal,
signedOrder.makerAddress,
unsupportedSignatureHex,
),
RevertReason.SignatureIllegal,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
unsupportedSignatureHex,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should return false when SignatureType=Invalid and signature has a length of zero', async () => { it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
@ -184,14 +194,16 @@ describe('MixinSignatureValidator', () => {
const signatureBuffer = Buffer.concat([fillerData, signatureType]); const signatureBuffer = Buffer.concat([fillerData, signatureType]);
const signatureHex = ethUtil.bufferToHex(signatureBuffer); const signatureHex = ethUtil.bufferToHex(signatureBuffer);
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync( orderHashHex,
orderHashHex, ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
signedOrder.makerAddress,
signatureHex,
),
RevertReason.Length0Required,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signedOrder.makerAddress,
signatureHex,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should return true when SignatureType=EIP712 and signature is valid', async () => { it('should return true when SignatureType=EIP712 and signature is valid', async () => {
@ -344,14 +356,16 @@ describe('MixinSignatureValidator', () => {
ethUtil.toBuffer(`0x${SignatureType.Wallet}`), ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
]); ]);
const signatureHex = ethUtil.bufferToHex(signature); const signatureHex = ethUtil.bufferToHex(signature);
await expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync( orderHashHex,
orderHashHex, ExchangeRevertErrors.SignatureErrorCode.WalletError,
maliciousWallet.address,
signatureHex,
),
RevertReason.WalletError,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
maliciousWallet.address,
signatureHex,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => {
@ -390,10 +404,16 @@ describe('MixinSignatureValidator', () => {
const signature = Buffer.concat([validatorAddress, signatureType]); const signature = Buffer.concat([validatorAddress, signatureType]);
const signatureHex = ethUtil.bufferToHex(signature); const signatureHex = ethUtil.bufferToHex(signature);
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
await expectContractCallFailedAsync( const expectedError = new ExchangeRevertErrors.SignatureError(
signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex), orderHashHex,
RevertReason.ValidatorError, ExchangeRevertErrors.SignatureErrorCode.ValidatorError,
); );
const tx = signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
signerAddress,
signatureHex,
);
return expect(tx).to.revertWith(expectedError);
}); });
it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => { it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
// Set approval of signature validator to false // Set approval of signature validator to false

View File

@ -4,7 +4,6 @@ import {
chaiSetup, chaiSetup,
constants, constants,
ERC20BalancesByOwner, ERC20BalancesByOwner,
expectTransactionFailedAsync,
OrderFactory, OrderFactory,
orderUtils, orderUtils,
provider, provider,
@ -17,10 +16,12 @@ import {
assetDataUtils, assetDataUtils,
ExchangeRevertErrors, ExchangeRevertErrors,
generatePseudoRandomSalt, generatePseudoRandomSalt,
orderHashUtils,
transactionHashUtils, transactionHashUtils,
} from '@0x/order-utils'; } from '@0x/order-utils';
import { import {
EIP712DomainWithDefaultSchema, EIP712DomainWithDefaultSchema,
OrderStatus,
OrderWithoutDomain, OrderWithoutDomain,
RevertReason, RevertReason,
SignedOrder, SignedOrder,
@ -36,7 +37,7 @@ chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe.only('Exchange transactions', () => { describe('Exchange transactions', () => {
let chainId: number; let chainId: number;
let senderAddress: string; let senderAddress: string;
let owner: string; let owner: string;
@ -153,9 +154,11 @@ describe.only('Exchange transactions', () => {
}); });
it('should throw if not called by specified sender', async () => { it('should throw if not called by specified sender', async () => {
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx); const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
const expectedError = new ExchangeRevertErrors.TransactionExecutionError( const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
transactionHashHex, transactionHashHex,
new ExchangeRevertErrors.InvalidSenderError(orderHashHex, takerAddress).encode(),
); );
const tx = exchangeWrapper.executeTransactionAsync(signedTx, takerAddress); const tx = exchangeWrapper.executeTransactionAsync(signedTx, takerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
@ -198,10 +201,13 @@ describe.only('Exchange transactions', () => {
it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => { it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
return expectTransactionFailedAsync( const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
exchangeWrapper.executeTransactionAsync(signedTx, senderAddress), const expectedError = new ExchangeRevertErrors.TransactionError(
RevertReason.InvalidTxHash, transactionHashHex,
ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted,
); );
const tx = exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
return expect(tx).to.revertWith(expectedError);
}); });
it('should reset the currentContextAddress', async () => { it('should reset the currentContextAddress', async () => {
@ -218,18 +224,25 @@ describe.only('Exchange transactions', () => {
}); });
it('should throw if not called by specified sender', async () => { it('should throw if not called by specified sender', async () => {
return expectTransactionFailedAsync( const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
exchangeWrapper.executeTransactionAsync(signedTx, makerAddress), const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
RevertReason.FailedExecution, const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
transactionHashHex,
new ExchangeRevertErrors.InvalidSenderError(orderHashHex, makerAddress).encode(),
); );
const tx = exchangeWrapper.executeTransactionAsync(signedTx, makerAddress);
return expect(tx).to.revertWith(expectedError);
}); });
it('should cancel the order when signed by maker and called by sender', async () => { it('should cancel the order when signed by maker and called by sender', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
return expectTransactionFailedAsync( const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
exchangeWrapper.fillOrderAsync(signedOrder, senderAddress), const expectedError = new ExchangeRevertErrors.OrderStatusError(
RevertReason.OrderUnfillable, orderHashHex,
OrderStatus.Cancelled,
); );
const tx = exchangeWrapper.fillOrderAsync(signedOrder, senderAddress);
return expect(tx).to.revertWith(expectedError);
}); });
}); });
@ -271,17 +284,21 @@ describe.only('Exchange transactions', () => {
signedOrder.signature, signedOrder.signature,
); );
const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData); const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData);
return expectTransactionFailedAsync( const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
exchangeWrapperContract.fillOrder.sendTransactionAsync( const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedFillTx);
orderWithoutDomain, const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
takerAssetFillAmount, transactionHashHex,
signedFillTx.salt, new ExchangeRevertErrors.OrderStatusError(orderHashHex, OrderStatus.Cancelled).encode(),
signedOrder.signature,
signedFillTx.signature,
{ from: takerAddress },
),
RevertReason.FailedExecution,
); );
const tx = exchangeWrapperContract.fillOrder.sendTransactionAsync(
orderWithoutDomain,
takerAssetFillAmount,
signedFillTx.salt,
signedOrder.signature,
signedFillTx.signature,
{ from: takerAddress },
);
return expect(tx).to.revertWith(expectedError);
}); });
it("should not cancel an order if not called from the order's sender", async () => { it("should not cancel an order if not called from the order's sender", async () => {
@ -391,16 +408,14 @@ describe.only('Exchange transactions', () => {
orderWithoutDomain = orderUtils.getOrderWithoutDomain(signedOrder); orderWithoutDomain = orderUtils.getOrderWithoutDomain(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount; const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt(); const salt = generatePseudoRandomSalt();
return expectTransactionFailedAsync( const tx = whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutDomain,
orderWithoutDomain, takerAssetFillAmount,
takerAssetFillAmount, salt,
salt, signedOrder.signature,
signedOrder.signature, { from: takerAddress },
{ from: takerAddress },
),
RevertReason.MakerNotWhitelisted,
); );
return expect(tx).to.revertWith(RevertReason.MakerNotWhitelisted);
}); });
it('should revert if taker has not been whitelisted', async () => { it('should revert if taker has not been whitelisted', async () => {
@ -413,16 +428,14 @@ describe.only('Exchange transactions', () => {
orderWithoutDomain = orderUtils.getOrderWithoutDomain(signedOrder); orderWithoutDomain = orderUtils.getOrderWithoutDomain(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount; const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt(); const salt = generatePseudoRandomSalt();
return expectTransactionFailedAsync( const tx = whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutDomain,
orderWithoutDomain, takerAssetFillAmount,
takerAssetFillAmount, salt,
salt, signedOrder.signature,
signedOrder.signature, { from: takerAddress },
{ from: takerAddress },
),
RevertReason.TakerNotWhitelisted,
); );
return expect(tx).to.revertWith(RevertReason.TakerNotWhitelisted);
}); });
it('should fill the order if maker and taker have been whitelisted', async () => { it('should fill the order if maker and taker have been whitelisted', async () => {

View File

@ -6,7 +6,6 @@ import {
BalanceAmountScenario, BalanceAmountScenario,
chaiSetup, chaiSetup,
constants, constants,
expectTransactionFailedAsync,
ExpirationTimeSecondsScenario, ExpirationTimeSecondsScenario,
FeeRecipientAddressScenario, FeeRecipientAddressScenario,
FillScenario, FillScenario,
@ -441,7 +440,11 @@ export class FillOrderCombinatorialUtils {
lazyStore: BalanceAndProxyAllowanceLazyStore, lazyStore: BalanceAndProxyAllowanceLazyStore,
fillRevertReasonIfExists: RevertReason | RevertError | undefined, fillRevertReasonIfExists: RevertReason | RevertError | undefined,
): Promise<void> { ): Promise<void> {
<<<<<<< HEAD
if (fillRevertReasonIfExists !== undefined) { if (fillRevertReasonIfExists !== undefined) {
=======
if (!_.isUndefined(fillRevertReasonIfExists)) {
>>>>>>> In `@0x/contracts-exchange`: Update tests for rich reverts
const tx = this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }); const tx = this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount });
return expect(tx).to.revertWith(fillRevertReasonIfExists); return expect(tx).to.revertWith(fillRevertReasonIfExists);
} }
@ -945,14 +948,14 @@ function validationErrorToRevertError(order: Order, reason: RevertReason): Rever
case RevertReason.InvalidTakerAmount: case RevertReason.InvalidTakerAmount:
return new ExchangeRevertErrors.FillError( return new ExchangeRevertErrors.FillError(
orderHash, orderHash,
ExchangeRevertErrors.FillErrorCodes.InvalidTakerAmount, ExchangeRevertErrors.FillErrorCode.InvalidTakerAmount,
); );
case RevertReason.TakerOverpay: case RevertReason.TakerOverpay:
return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCodes.TakerOverpay); return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCode.TakerOverpay);
case RevertReason.OrderOverfill: case RevertReason.OrderOverfill:
return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCodes.Overfill); return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCode.Overfill);
case RevertReason.InvalidFillPrice: case RevertReason.InvalidFillPrice:
return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCodes.InvalidFillPrice); return new ExchangeRevertErrors.FillError(orderHash, ExchangeRevertErrors.FillErrorCode.InvalidFillPrice);
case RevertReason.TransferFailed: case RevertReason.TransferFailed:
return new ExchangeRevertErrors.AssetProxyTransferError(orderHash, undefined, 'TRANSFER_FAILED'); return new ExchangeRevertErrors.AssetProxyTransferError(orderHash, undefined, 'TRANSFER_FAILED');
default: default:

View File

@ -5,18 +5,16 @@ import {
chaiSetup, chaiSetup,
constants, constants,
ERC20BalancesByOwner, ERC20BalancesByOwner,
expectTransactionFailedAsync,
getLatestBlockTimestampAsync, getLatestBlockTimestampAsync,
increaseTimeAndMineBlockAsync, increaseTimeAndMineBlockAsync,
OrderFactory, OrderFactory,
OrderStatus,
provider, provider,
txDefaults, txDefaults,
web3Wrapper, web3Wrapper,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils'; import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { assetDataUtils, ExchangeRevertErrors, orderHashUtils } from '@0x/order-utils';
import { RevertReason, SignedOrder } from '@0x/types'; import { OrderStatus, RevertReason, SignedOrder } from '@0x/types';
import { BigNumber, providerUtils } from '@0x/utils'; import { BigNumber, providerUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper'; import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai'; import * as chai from 'chai';
@ -152,10 +150,8 @@ describe('Exchange wrappers', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress);
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
RevertReason.ReentrancyIllegal,
);
}); });
}); });
}; };
@ -210,11 +206,13 @@ describe('Exchange wrappers', () => {
const signedOrder = await orderFactory.newSignedOrderAsync({ const signedOrder = await orderFactory.newSignedOrderAsync({
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
}); });
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectTransactionFailedAsync( const expectedError = new ExchangeRevertErrors.OrderStatusError(
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), orderHashHex,
RevertReason.OrderUnfillable, OrderStatus.Expired,
); );
const tx = exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError);
}); });
it('should throw if entire takerAssetFillAmount not filled', async () => { it('should throw if entire takerAssetFillAmount not filled', async () => {
@ -224,10 +222,12 @@ describe('Exchange wrappers', () => {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
}); });
return expectTransactionFailedAsync( const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), const expectedError = new ExchangeRevertErrors.IncompleteFillError(
RevertReason.CompleteFillFailed, orderHashHex,
); );
const tx = exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError);
}); });
}); });
@ -462,10 +462,8 @@ describe('Exchange wrappers', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress);
exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress), return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
RevertReason.ReentrancyIllegal,
);
}); });
}); });
}; };
@ -531,10 +529,8 @@ describe('Exchange wrappers', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress);
exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress), return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
RevertReason.ReentrancyIllegal,
);
}); });
}); });
}; };
@ -595,13 +591,17 @@ describe('Exchange wrappers', () => {
}); });
await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress); await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrders[0]);
return expectTransactionFailedAsync( const expectedError = new ExchangeRevertErrors.OrderStatusError(
exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, { orderHashHex,
takerAssetFillAmounts, OrderStatus.FullyFilled,
}),
RevertReason.OrderUnfillable,
); );
const tx = exchangeWrapper.batchFillOrKillOrdersAsync(
signedOrders,
takerAddress,
{ takerAssetFillAmounts },
);
return expect(tx).to.revertWith(expectedError);
}); });
}); });
@ -749,12 +749,12 @@ describe('Exchange wrappers', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.marketSellOrdersAsync(
exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, { [signedOrder],
takerAssetFillAmount: signedOrder.takerAssetAmount, takerAddress,
}), { takerAssetFillAmount: signedOrder.takerAssetAmount},
RevertReason.ReentrancyIllegal,
); );
return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
}); });
}); });
}; };
@ -839,15 +839,21 @@ describe('Exchange wrappers', () => {
}), }),
await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync(),
]; ];
const reconstructedOrder = {
return expectTransactionFailedAsync( ...signedOrders[1],
exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, { takerAssetData: signedOrders[0].takerAssetData,
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), };
}), const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrder);
// We simply use the takerAssetData from the first order for all orders. const expectedError = new ExchangeRevertErrors.SignatureError(
// If they are not the same, the contract throws when validating the order signature orderHashHex,
RevertReason.InvalidOrderSignature, ExchangeRevertErrors.SignatureErrorCode.BadSignature,
); );
const tx = exchangeWrapper.marketSellOrdersAsync(
signedOrders,
takerAddress,
{ takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18) },
);
return expect(tx).to.revertWith(expectedError);
}); });
}); });
@ -1010,12 +1016,12 @@ describe('Exchange wrappers', () => {
await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId), await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await expectTransactionFailedAsync( const tx = exchangeWrapper.marketBuyOrdersAsync(
exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, { [signedOrder],
makerAssetFillAmount: signedOrder.makerAssetAmount, takerAddress,
}), { makerAssetFillAmount: signedOrder.makerAssetAmount },
RevertReason.ReentrancyIllegal,
); );
return expect(tx).to.revertWith(RevertReason.ReentrancyIllegal);
}); });
}); });
}; };
@ -1100,13 +1106,21 @@ describe('Exchange wrappers', () => {
}), }),
await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync(),
]; ];
const reconstructedOrder = {
return expectTransactionFailedAsync( ...signedOrders[1],
exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, { makerAssetData: signedOrders[0].makerAssetData,
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), };
}), const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrder);
RevertReason.InvalidOrderSignature, const expectedError = new ExchangeRevertErrors.SignatureError(
orderHashHex,
ExchangeRevertErrors.SignatureErrorCode.BadSignature,
); );
const tx = exchangeWrapper.marketBuyOrdersAsync(
signedOrders,
takerAddress,
{ makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18) },
);
return expect(tx).to.revertWith(expectedError);
}); });
}); });