update tests to use RevertErrors

This commit is contained in:
Michael Zhu
2019-08-08 14:46:03 -07:00
parent c9f0c46017
commit f8025feda2
8 changed files with 256 additions and 185 deletions

View File

@@ -245,10 +245,10 @@ contract MixinExchangeWrapper is
}
}
require(
totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount,
"COMPLETE_FILL_FAILED"
);
if (totalFillResults.makerAssetFilledAmount < makerAssetFillAmount) {
LibRichErrors._rrevert(LibForwarderRichErrors.CompleteFillFailedError());
}
return (totalFillResults, wethSpentAmount, makerAssetAcquiredAmount);
}
}

View File

@@ -89,10 +89,7 @@ contract MixinWeth is
// Ensure fee is less than amount of WETH remaining.
if (ethFee > wethRemaining) {
LibRichErrors._rrevert(LibForwarderRichErrors.InsufficientEthRemainingError(
ethFee,
wethRemaining
));
LibRichErrors._rrevert(LibForwarderRichErrors.InsufficientEthForFeeError());
}
// Do nothing if no WETH remaining

View File

@@ -23,10 +23,6 @@ import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
library LibForwarderRichErrors {
// bytes4(keccak256("UnregisteredAssetProxyError()"))
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
0xf3b96b8d;
// bytes4(keccak256("UnregisteredAssetProxyError()"))
bytes internal constant UNREGISTERED_ASSET_PROXY_ERROR =
hex"f3b96b8d";
@@ -35,9 +31,9 @@ library LibForwarderRichErrors {
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
0x7996a271;
// bytes4(keccak256("CompleteFillFailedError(uint256,uint256)"))
bytes4 internal constant COMPLETE_FILL_FAILED_ERROR_SELECTOR =
0x7675a605;
// bytes4(keccak256("CompleteFillFailedError()"))
bytes internal constant COMPLETE_FILL_FAILED_ERROR =
hex"4bcb2058";
// bytes4(keccak256("MakerAssetMismatchError(bytes,bytes)"))
bytes4 internal constant MAKER_ASSET_MISMATCH_ERROR_SELECTOR =
@@ -47,18 +43,14 @@ library LibForwarderRichErrors {
bytes4 internal constant FEE_PERCENTAGE_TOO_LARGE_ERROR_SELECTOR =
0x1174fb80;
// bytes4(keccak256("InsufficientEthRemainingError(uint256,uint256)"))
bytes4 internal constant INSUFFICIENT_ETH_REMAINING_ERROR_SELECTOR =
0x01b718a6;
// bytes4(keccak256("InsufficientEthForFeeError()"))
bytes internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR =
hex"54a53d9e";
// bytes4(keccak256("OversoldWethError(uint256,uint256)"))
bytes4 internal constant OVERSOLD_WETH_ERROR_SELECTOR =
0x5cc555c8;
// bytes4(keccak256("TransferFailedError()"))
bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR =
0x570f1df4;
// bytes4(keccak256("TransferFailedError()"))
bytes internal constant TRANSFER_FAILED_ERROR =
hex"570f1df4";
@@ -101,19 +93,12 @@ library LibForwarderRichErrors {
);
}
function CompleteFillFailedError(
uint256 desiredFillAmount,
uint256 actualFillAmount
)
function CompleteFillFailedError()
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
COMPLETE_FILL_FAILED_ERROR_SELECTOR,
desiredFillAmount,
actualFillAmount
);
return COMPLETE_FILL_FAILED_ERROR;
}
function MakerAssetMismatchError(
@@ -144,19 +129,12 @@ library LibForwarderRichErrors {
);
}
function InsufficientEthRemainingError(
uint256 ethFee,
uint256 wethRemaining
)
function InsufficientEthForFeeError()
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INSUFFICIENT_ETH_REMAINING_ERROR_SELECTOR,
ethFee,
wethRemaining
);
return INSUFFICIENT_ETH_FOR_FEE_ERROR;
}
function OversoldWethError(

View File

@@ -14,7 +14,7 @@ import {
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils } from '@0x/order-utils';
import { assetDataUtils, ForwarderRevertErrors } from '@0x/order-utils';
import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber, providerUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
@@ -123,12 +123,12 @@ describe(ContractName.Forwarder, () => {
feeRecipientAddress: orderFeeRecipientAddress,
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT),
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(200, DECIMALS_DEFAULT),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, DECIMALS_DEFAULT),
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT),
makerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
domain: {
verifyingContractAddress: exchangeInstance.address,
chainId,
@@ -169,11 +169,11 @@ describe(ContractName.Forwarder, () => {
await blockchainLifecycle.startAsync();
orderWithoutFee = await orderFactory.newSignedOrderAsync();
orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
orderWithWethFee = await orderFactory.newSignedOrderAsync({
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
takerFeeAssetData: wethAssetData,
});
});
@@ -189,16 +189,16 @@ describe(ContractName.Forwarder, () => {
txDefaults,
new BigNumber(chainId),
);
return expectContractCreationFailedAsync(
(ForwarderContract.deployFrom0xArtifactAsync(
artifacts.Forwarder,
provider,
txDefaults,
exchangeInstance.address,
wethAssetData,
) as any) as sendTransactionResult,
RevertReason.UnregisteredAssetProxy,
);
const deployForwarder = (ForwarderContract.deployFrom0xArtifactAsync(
artifacts.Forwarder,
provider,
txDefaults,
exchangeInstance.address,
wethAssetData,
) as any) as sendTransactionResult;
expect(deployForwarder).to.revertWith(new ForwarderRevertErrors.UnregisteredAssetProxyError());
});
});
describe('marketSellOrdersWithEth without extra fees', () => {
@@ -215,7 +215,7 @@ describe(ContractName.Forwarder, () => {
});
it('should fill multiple orders with percentage fees', async () => {
const secondOrderWithPercentageFee = await orderFactory.newSignedOrderAsync({
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(2, DECIMALS_DEFAULT),
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
const orders = [orderWithPercentageFee, secondOrderWithPercentageFee];
@@ -225,7 +225,7 @@ describe(ContractName.Forwarder, () => {
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
const order = await orderFactory.newSignedOrderAsync({
makerAssetData: unapprovedAsset,
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(2, DECIMALS_DEFAULT),
takerFeeAssetData: unapprovedAsset,
});
@@ -266,7 +266,7 @@ describe(ContractName.Forwarder, () => {
});
it('should fill multiple orders with WETH fees', async () => {
const secondOrderWithPercentageFee = await orderFactory.newSignedOrderAsync({
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(2, DECIMALS_DEFAULT),
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
const orders = [orderWithWethFee, secondOrderWithPercentageFee];
@@ -287,16 +287,26 @@ describe(ContractName.Forwarder, () => {
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
});
it('should not fill orders with different makerAssetData than the first order', async () => {
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress);
const erc20SignedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData: firstOrderMakerAssetData,
});
const makerAssetId = erc721MakerAssetIds[0];
const secondOrderMakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId);
const erc721SignedOrder = await orderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
makerAssetData: secondOrderMakerAssetData,
});
const erc20SignedOrder = await orderFactory.newSignedOrderAsync();
const orders = [erc20SignedOrder, erc721SignedOrder];
const revertError = new ForwarderRevertErrors.MakerAssetMismatchError(
firstOrderMakerAssetData,
secondOrderMakerAssetData,
);
await forwarderTestFactory.marketSellTestAsync(orders, new BigNumber(2), erc20Token, {
revertReason: RevertReason.MakerAssetMismatch,
revertError,
});
});
});
@@ -307,9 +317,14 @@ describe(ContractName.Forwarder, () => {
});
});
it('should fail if the fee is set too high', async () => {
const forwarderFeePercentage = new BigNumber(6);
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
);
await forwarderTestFactory.marketSellTestAsync([orderWithoutFee], new BigNumber(0.5), erc20Token, {
forwarderFeePercentage: new BigNumber(6),
revertReason: RevertReason.FeePercentageTooLarge,
forwarderFeePercentage,
revertError,
});
});
});
@@ -324,7 +339,7 @@ describe(ContractName.Forwarder, () => {
});
it('should buy the exact amount of makerAsset and return excess ETH', async () => {
await forwarderTestFactory.marketBuyTestAsync([orderWithoutFee], new BigNumber(0.5), erc20Token, {
ethValueAdjustment: orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2),
ethValueAdjustment: new BigNumber(2),
});
});
it('should buy the exact amount of makerAsset from a single order with a WETH fee', async () => {
@@ -334,9 +349,10 @@ describe(ContractName.Forwarder, () => {
await forwarderTestFactory.marketBuyTestAsync([orderWithPercentageFee], new BigNumber(0.5), erc20Token);
});
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
const revertError = new ForwarderRevertErrors.CompleteFillFailedError();
await forwarderTestFactory.marketBuyTestAsync([orderWithoutFee], new BigNumber(0.5), erc20Token, {
ethValueAdjustment: new BigNumber(-1),
revertReason: RevertReason.CompleteFillFailed,
ethValueAdjustment: new BigNumber(-2),
revertError,
});
});
it('should buy an ERC721 asset from a single order', async () => {
@@ -349,26 +365,12 @@ describe(ContractName.Forwarder, () => {
makerAssetId,
});
});
it('should revert if buying an ERC721 asset when later orders contain different makerAssetData', async () => {
const makerAssetId = erc721MakerAssetIds[0];
const erc721Order = await orderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
});
const differentMakerAssetDataOrder = await orderFactory.newSignedOrderAsync();
const orders = [erc721Order, differentMakerAssetDataOrder];
await forwarderTestFactory.marketBuyTestAsync(orders, new BigNumber(2), erc721Token, {
makerAssetId,
revertReason: RevertReason.MakerAssetMismatch,
});
});
it('should buy an ERC721 asset and pay WETH fees from a single fee order', async () => {
const makerAssetId = erc721MakerAssetIds[0];
const erc721orderWithWethFee = await orderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
takerFeeAssetData: wethAssetData,
});
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], new BigNumber(1), erc721Token, {
@@ -494,16 +496,20 @@ describe(ContractName.Forwarder, () => {
});
});
it('should fail if the fee is set too high', async () => {
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
);
await forwarderTestFactory.marketBuyTestAsync([orderWithoutFee], new BigNumber(0.5), erc20Token, {
forwarderFeePercentage: new BigNumber(6),
revertReason: RevertReason.FeePercentageTooLarge,
revertError,
});
});
it('should fail if there is not enough ETH remaining to pay the fee', async () => {
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError();
await forwarderTestFactory.marketBuyTestAsync([orderWithoutFee], new BigNumber(0.5), erc20Token, {
ethValueAdjustment: new BigNumber(-1),
ethValueAdjustment: new BigNumber(-2),
forwarderFeePercentage: new BigNumber(2),
revertReason: RevertReason.InsufficientEthRemaining,
revertError,
});
});
});

View File

@@ -1,17 +1,10 @@
import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
import {
chaiSetup,
constants,
ERC20BalancesByOwner,
expectTransactionFailedAsync,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { chaiSetup, constants, ERC20BalancesByOwner, web3Wrapper } from '@0x/contracts-test-utils';
import { SignedOrder } from '@0x/types';
import { BigNumber, RevertError } from '@0x/utils';
import * as chai from 'chai';
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { ForwarderWrapper } from './forwarder_wrapper';
@@ -43,49 +36,47 @@ function computeExpectedResults(orders: SignedOrder[], fractionalNumberOfOrdersT
};
let remainingOrdersToFill = fractionalNumberOfOrdersToFill;
_.forEach(
orders,
(order: SignedOrder): void => {
if (remainingOrdersToFill.isEqualTo(constants.ZERO_AMOUNT)) {
return;
}
for (const order of orders) {
if (remainingOrdersToFill.isEqualTo(constants.ZERO_AMOUNT)) {
break;
}
let makerAssetAmount;
let takerAssetAmount;
let takerFee;
if (remainingOrdersToFill.isLessThan(new BigNumber(1))) {
const [partialFillNumerator, partialFillDenominator] = remainingOrdersToFill.toFraction();
makerAssetAmount = order.makerAssetAmount
.times(partialFillNumerator)
.dividedToIntegerBy(partialFillDenominator);
takerAssetAmount = order.takerAssetAmount
.times(partialFillNumerator)
.dividedToIntegerBy(partialFillDenominator);
takerFee = order.takerFee.times(partialFillNumerator).dividedToIntegerBy(partialFillDenominator);
} else {
makerAssetAmount = order.makerAssetAmount;
takerAssetAmount = order.takerAssetAmount;
takerFee = order.takerFee;
}
let makerAssetAmount;
let takerAssetAmount;
let takerFee;
if (remainingOrdersToFill.isLessThan(new BigNumber(1))) {
const [partialFillNumerator, partialFillDenominator] = remainingOrdersToFill.toFraction();
makerAssetAmount = order.makerAssetAmount
.times(partialFillNumerator)
.dividedToIntegerBy(partialFillDenominator);
takerAssetAmount = order.takerAssetAmount
.times(partialFillNumerator)
.dividedToIntegerBy(partialFillDenominator);
takerFee = order.takerFee.times(partialFillNumerator).dividedToIntegerBy(partialFillDenominator);
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
currentState.makerAssetFillAmount = currentState.makerAssetFillAmount.plus(makerAssetAmount);
// Up to 1 wei worth of WETH will be oversold on the last order due to rounding
currentState.maxOversoldWeth = new BigNumber(1);
// Equivalently, up to 1 wei worth of maker asset will be overbought per order
currentState.maxOverboughtMakerAsset = currentState.maxOversoldWeth
.times(order.makerAssetAmount)
.dividedToIntegerBy(order.takerAssetAmount);
} else {
makerAssetAmount = order.makerAssetAmount;
takerAssetAmount = order.takerAssetAmount;
takerFee = order.takerFee;
}
if (order.takerFeeAssetData === order.makerAssetData) {
currentState.percentageFees = currentState.percentageFees.plus(takerFee);
} else if (order.takerFeeAssetData === order.takerAssetData) {
currentState.wethFees = currentState.wethFees.plus(takerFee);
// Up to 1 wei worth of WETH will be oversold per order due to rounding
currentState.maxOversoldWeth = currentState.maxOversoldWeth.plus(new BigNumber(1));
// Equivalently, up to 1 wei worth of maker asset will be overbought per order
currentState.maxOverboughtMakerAsset = currentState.maxOversoldWeth
.times(makerAssetAmount)
.dividedToIntegerBy(takerAssetAmount);
}
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
currentState.makerAssetFillAmount = currentState.makerAssetFillAmount.plus(makerAssetAmount);
remainingOrdersToFill = BigNumber.max(remainingOrdersToFill.minus(new BigNumber(1)), constants.ZERO_AMOUNT);
},
);
if (order.takerFeeAssetData === order.makerAssetData) {
currentState.percentageFees = currentState.percentageFees.plus(takerFee);
} else if (order.takerFeeAssetData === order.takerAssetData) {
currentState.wethFees = currentState.wethFees.plus(takerFee);
}
remainingOrdersToFill = BigNumber.max(remainingOrdersToFill.minus(new BigNumber(1)), constants.ZERO_AMOUNT);
}
return currentState;
}
@@ -143,7 +134,7 @@ export class ForwarderTestFactory {
ethValueAdjustment?: BigNumber; // Used to provided insufficient/excess ETH
forwarderFeePercentage?: BigNumber;
makerAssetId?: BigNumber;
revertReason?: RevertReason;
revertError?: RevertError;
} = {},
): Promise<void> {
const ethValueAdjustment = options.ethValueAdjustment || constants.ZERO_AMOUNT;
@@ -171,23 +162,7 @@ export class ForwarderTestFactory {
.plus(ethSpentOnForwarderFee)
.plus(ethValueAdjustment);
if (options.revertReason !== undefined) {
await expectTransactionFailedAsync(
this._forwarderWrapper.marketBuyOrdersWithEthAsync(
orders,
expectedResults.makerAssetFillAmount,
{
value: ethValue,
from: this._takerAddress,
},
{ feePercentage, feeRecipient: this._forwarderFeeRecipientAddress },
),
options.revertReason,
);
return;
}
const tx = await this._forwarderWrapper.marketBuyOrdersWithEthAsync(
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
orders,
expectedResults.makerAssetFillAmount,
{
@@ -197,11 +172,23 @@ export class ForwarderTestFactory {
{ feePercentage, feeRecipient: this._forwarderFeeRecipientAddress },
);
await this._checkResultsAsync(tx, expectedResults, takerEthBalanceBefore, erc20Balances, makerAssetContract, {
forwarderFeePercentage,
forwarderFeeRecipientEthBalanceBefore,
makerAssetId: options.makerAssetId,
});
if (options.revertError !== undefined) {
await expect(tx).to.revertWith(options.revertError);
} else {
const gasUsed = (await tx).gasUsed;
await this._checkResultsAsync(
gasUsed,
expectedResults,
takerEthBalanceBefore,
erc20Balances,
makerAssetContract,
{
forwarderFeePercentage,
forwarderFeeRecipientEthBalanceBefore,
makerAssetId: options.makerAssetId,
},
);
}
}
public async marketSellTestAsync(
@@ -210,7 +197,7 @@ export class ForwarderTestFactory {
makerAssetContract: DummyERC20TokenContract,
options: {
forwarderFeePercentage?: BigNumber;
revertReason?: RevertReason;
revertError?: RevertError;
} = {},
): Promise<void> {
const forwarderFeePercentage = options.forwarderFeePercentage || constants.ZERO_AMOUNT;
@@ -236,22 +223,7 @@ export class ForwarderTestFactory {
.plus(expectedResults.maxOversoldWeth)
.plus(ethSpentOnForwarderFee);
if (options.revertReason !== undefined) {
await expectTransactionFailedAsync(
this._forwarderWrapper.marketSellOrdersWithEthAsync(
orders,
{
value: ethValue,
from: this._takerAddress,
},
{ feePercentage, feeRecipient: this._forwarderFeeRecipientAddress },
),
options.revertReason,
);
return;
}
const tx = await this._forwarderWrapper.marketSellOrdersWithEthAsync(
const tx = this._forwarderWrapper.marketSellOrdersWithEthAsync(
orders,
{
value: ethValue,
@@ -260,10 +232,22 @@ export class ForwarderTestFactory {
{ feePercentage, feeRecipient: this._forwarderFeeRecipientAddress },
);
await this._checkResultsAsync(tx, expectedResults, takerEthBalanceBefore, erc20Balances, makerAssetContract, {
forwarderFeePercentage,
forwarderFeeRecipientEthBalanceBefore,
});
if (options.revertError !== undefined) {
await expect(tx).to.revertWith(options.revertError);
} else {
const gasUsed = (await tx).gasUsed;
await this._checkResultsAsync(
gasUsed,
expectedResults,
takerEthBalanceBefore,
erc20Balances,
makerAssetContract,
{
forwarderFeePercentage,
forwarderFeeRecipientEthBalanceBefore,
},
);
}
}
private _checkErc20Balances(
@@ -297,7 +281,7 @@ export class ForwarderTestFactory {
}
private async _checkResultsAsync(
tx: TransactionReceiptWithDecodedLogs,
gasUsed: number,
expectedResults: ForwarderFillState,
takerEthBalanceBefore: BigNumber,
erc20Balances: ERC20BalancesByOwner,
@@ -315,7 +299,7 @@ export class ForwarderTestFactory {
const totalEthSpent = expectedResults.takerAssetFillAmount
.plus(expectedResults.wethFees)
.plus(ethSpentOnForwarderFee)
.plus(this._gasPrice.times(tx.gasUsed));
.plus(this._gasPrice.times(gasUsed));
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(this._takerAddress);
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(this._forwarderAddress);

View File

@@ -1,5 +1,5 @@
import { RevertReason } from '@0x/types';
import { logUtils } from '@0x/utils';
import { logUtils, RevertError } from '@0x/utils';
import { NodeType } from '@0x/web3-wrapper';
import * as chai from 'chai';
import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
@@ -90,7 +90,7 @@ export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<vo
* @returns a new Promise which will reject if the conditions are not met and
* otherwise resolve with no value.
*/
export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> {
export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason | RevertError): Promise<void> {
// HACK(albrow): This dummy `catch` should not be necessary, but if you
// remove it, there is an uncaught exception and the Node process will
// forcibly exit. It's possible this is a false positive in
@@ -184,7 +184,7 @@ export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T
*/
export async function expectContractCreationFailedAsync<T>(
p: sendTransactionResult,
reason: RevertReason,
reason: RevertReason | RevertError,
): Promise<void> {
return expectTransactionFailedAsync(p, reason);
}

View File

@@ -0,0 +1,105 @@
import { BigNumber, RevertError } from '@0x/utils';
import * as _ from 'lodash';
// tslint:disable:max-classes-per-file
export class UnregisteredAssetProxyError extends RevertError {
constructor() {
super('UnregisteredAssetProxyError', 'UnregisteredAssetProxyError()', {});
}
}
export class UnsupportedAssetProxyError extends RevertError {
constructor(proxyId?: string) {
super('UnsupportedAssetProxyError', 'UnsupportedAssetProxyError(bytes4 proxyId)', { proxyId });
}
}
export class CompleteFillFailedError extends RevertError {
constructor() {
super('CompleteFillFailedError', 'CompleteFillFailedError()', {});
}
}
export class MakerAssetMismatchError extends RevertError {
constructor(firstOrderMakerAssetData?: string, mismatchedMakerAssetData?: string) {
super(
'MakerAssetMismatchError',
'MakerAssetMismatchError(bytes firstOrderMakerAssetData, bytes mismatchedMakerAssetData)',
{
firstOrderMakerAssetData,
mismatchedMakerAssetData,
},
);
}
}
export class FeePercentageTooLargeError extends RevertError {
constructor(feePercentage?: BigNumber | number | string) {
super('FeePercentageTooLargeError', 'FeePercentageTooLargeError(uint256 feePercentage)', {
feePercentage,
});
}
}
export class InsufficientEthForFeeError extends RevertError {
constructor() {
super('InsufficientEthForFeeError', 'InsufficientEthForFeeError()', {});
}
}
export class OversoldWethError extends RevertError {
constructor(wethSold?: BigNumber | number | string, msgValue?: BigNumber | number | string) {
super('OversoldWethError', 'OversoldWethError(uint256 wethSold, uint256 msgValue)', {
wethSold,
msgValue,
});
}
}
export class TransferFailedError extends RevertError {
constructor() {
super('TransferFailedError', 'TransferFailedError()', {});
}
}
export class DefaultFunctionWethContractOnlyError extends RevertError {
constructor(callerAddress?: string) {
super('DefaultFunctionWethContractOnlyError', 'DefaultFunctionWethContractOnlyError(address callerAddress)', {
callerAddress,
});
}
}
export class InvalidMsgValueError extends RevertError {
constructor() {
super('InvalidMsgValueError', 'InvalidMsgValueError()', {});
}
}
export class InvalidErc721AmountError extends RevertError {
constructor(amount?: BigNumber | number | string) {
super('InvalidErc721AmountError', 'InvalidErc721AmountError(uint256 amount)', {
amount,
});
}
}
const types = [
UnregisteredAssetProxyError,
UnsupportedAssetProxyError,
CompleteFillFailedError,
MakerAssetMismatchError,
FeePercentageTooLargeError,
InsufficientEthForFeeError,
OversoldWethError,
TransferFailedError,
DefaultFunctionWethContractOnlyError,
InvalidMsgValueError,
InvalidErc721AmountError,
];
// Register the types we've defined.
for (const type of types) {
RevertError.registerType(type);
}

View File

@@ -1,4 +1,5 @@
import * as ExchangeRevertErrors from './exchange_revert_errors';
import * as ForwarderRevertErrors from './forwarder_revert_errors';
import * as LibMathRevertErrors from './lib_math_revert_errors';
export { orderHashUtils } from './order_hash';
@@ -85,4 +86,4 @@ export {
} from './types';
export { ExchangeContract, NetworkId } from '@0x/abi-gen-wrappers';
export { ExchangeRevertErrors, LibMathRevertErrors };
export { ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors };