update tests to use RichErrors

This commit is contained in:
Michael Zhu 2019-08-23 17:16:21 -07:00
parent 98e5b26eb7
commit dbda3a04b2
9 changed files with 120 additions and 90 deletions

View File

@ -1,6 +1,6 @@
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { chaiSetup } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber, RevertError } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
@ -9,6 +9,7 @@ import { DelegatorBalances, StakerBalances } from '../utils/types';
import { StakerActor } from './staker_actor';
chaiSetup.configure();
const expect = chai.expect;
export class DelegatorActor extends StakerActor {
@ -18,7 +19,7 @@ export class DelegatorActor extends StakerActor {
public async depositZrxAndDelegateToStakingPoolAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// query init balances
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
@ -29,8 +30,8 @@ export class DelegatorActor extends StakerActor {
poolId,
amount,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -54,14 +55,14 @@ export class DelegatorActor extends StakerActor {
public async activateAndDelegateStakeAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// query init balances
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
// activate and delegate
const txReceiptPromise = this._stakingWrapper.activateAndDelegateStakeAsync(this._owner, poolId, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -89,7 +90,7 @@ export class DelegatorActor extends StakerActor {
public async deactivateAndTimeLockDelegatedStakeAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// query init balances
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
@ -99,8 +100,8 @@ export class DelegatorActor extends StakerActor {
poolId,
amount,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;

View File

@ -1,5 +1,6 @@
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { chaiSetup } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { RevertError } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
@ -8,6 +9,7 @@ import { StakingWrapper } from '../utils/staking_wrapper';
import { BaseActor } from './base_actor';
chaiSetup.configure();
const expect = chai.expect;
export class PoolOperatorActor extends BaseActor {
@ -15,13 +17,13 @@ export class PoolOperatorActor extends BaseActor {
super(owner, stakingWrapper);
}
public async createStakingPoolAsync(operatorShare: number, revertReason?: RevertReason): Promise<string> {
public async createStakingPoolAsync(operatorShare: number, revertError?: RevertError): Promise<string> {
// query next pool id
const nextPoolId = await this._stakingWrapper.getNextStakingPoolIdAsync();
// create pool
const poolIdPromise = this._stakingWrapper.createStakingPoolAsync(this._owner, operatorShare);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(poolIdPromise, revertReason);
if (revertError !== undefined) {
await expect(poolIdPromise).to.revertWith(revertError);
return '';
}
const poolId = await poolIdPromise;
@ -33,7 +35,7 @@ export class PoolOperatorActor extends BaseActor {
poolId: string,
makerAddress: string,
makerSignature: string,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// add maker
const txReceiptPromise = this._stakingWrapper.addMakerToStakingPoolAsync(
@ -42,8 +44,8 @@ export class PoolOperatorActor extends BaseActor {
makerSignature,
this._owner,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -57,7 +59,7 @@ export class PoolOperatorActor extends BaseActor {
public async removeMakerFromStakingPoolAsync(
poolId: string,
makerAddress: string,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// remove maker
const txReceiptPromise = this._stakingWrapper.removeMakerFromStakingPoolAsync(
@ -65,8 +67,8 @@ export class PoolOperatorActor extends BaseActor {
makerAddress,
this._owner,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;

View File

@ -1,6 +1,6 @@
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { chaiSetup } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber, RevertError } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
@ -9,24 +9,25 @@ import { StakerBalances } from '../utils/types';
import { BaseActor } from './base_actor';
chaiSetup.configure();
const expect = chai.expect;
export class StakerActor extends BaseActor {
constructor(owner: string, stakingWrapper: StakingWrapper) {
super(owner, stakingWrapper);
}
public async depositZrxAndMintDeactivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async depositZrxAndMintDeactivatedStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
await this._stakingWrapper.depositZrxAndMintDeactivatedStakeAsync(this._owner, amount);
throw new Error('Checks Unimplemented');
}
public async depositZrxAndMintActivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async depositZrxAndMintActivatedStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
// query init balances
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
const initStakerBalances = await this.getBalancesAsync();
// deposit stake
const txReceiptPromise = this._stakingWrapper.depositZrxAndMintActivatedStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -42,13 +43,13 @@ export class StakerActor extends BaseActor {
const finalZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
expect(finalZrxBalanceOfVault).to.be.bignumber.equal(initZrxBalanceOfVault.plus(amount));
}
public async activateStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async activateStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
// query init balances
const initStakerBalances = await this.getBalancesAsync();
// activate stake
const txReceiptPromise = this._stakingWrapper.activateStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -61,13 +62,13 @@ export class StakerActor extends BaseActor {
expectedStakerBalances.deactivatedStakeBalance = initStakerBalances.deactivatedStakeBalance.minus(amount);
await this.assertBalancesAsync(expectedStakerBalances);
}
public async deactivateAndTimeLockStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async deactivateAndTimeLockStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
// query init balances
const initStakerBalances = await this.getBalancesAsync();
// deactivate and timeLock stake
const txReceiptPromise = this._stakingWrapper.deactivateAndTimeLockStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;
@ -81,15 +82,15 @@ export class StakerActor extends BaseActor {
}
public async burnDeactivatedStakeAndWithdrawZrxAsync(
amount: BigNumber,
revertReason?: RevertReason,
revertError?: RevertError,
): Promise<void> {
// query init balances
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
const initStakerBalances = await this.getBalancesAsync();
// withdraw stake
const txReceiptPromise = this._stakingWrapper.burnDeactivatedStakeAndWithdrawZrxAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
if (revertError !== undefined) {
await expect(txReceiptPromise).to.revertWith(revertError);
return;
}
await txReceiptPromise;

View File

@ -1,8 +1,8 @@
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
@ -64,19 +64,17 @@ describe('Exchange Integrations', () => {
const isValidAddressValid = await stakingWrapper.isValidExchangeAddressAsync(exchange);
expect(isValidAddressValid).to.be.true();
// 3 try adding valid address again
await expectTransactionFailedAsync(
stakingWrapper.addExchangeAddressAsync(exchange),
RevertReason.ExchangeAddressAlreadyRegistered,
);
let revertError = new StakingRevertErrors.ExchangeAddressAlreadyRegisteredError(exchange);
let tx = stakingWrapper.addExchangeAddressAsync(exchange);
await expect(tx).to.revertWith(revertError);
// 4 remove valid address
await stakingWrapper.removeExchangeAddressAsync(exchange);
const isValidAddressStillValid = await stakingWrapper.isValidExchangeAddressAsync(exchange);
expect(isValidAddressStillValid).to.be.false();
// 5 try removing valid address again
await expectTransactionFailedAsync(
stakingWrapper.removeExchangeAddressAsync(exchange),
RevertReason.ExchangeAddressNotRegistered,
);
revertError = new StakingRevertErrors.ExchangeAddressNotRegisteredError(exchange);
tx = stakingWrapper.removeExchangeAddressAsync(exchange);
await expect(tx).to.revertWith(revertError);
// @todo should not be able to add / remove an exchange if not contract owner.
});
});

View File

@ -1,8 +1,8 @@
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util';
@ -128,12 +128,13 @@ describe('Staking Pool Management', () => {
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature);
const revertError = new StakingRevertErrors.MakerAddressAlreadyRegisteredError(makerAddress);
// add same maker to pool again
await poolOperator.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.MakerAddressAlreadyRegistered,
revertError,
);
});
it('Should fail to remove a maker that does not exist', async () => {
@ -145,11 +146,16 @@ describe('Staking Pool Management', () => {
// create pool
const poolId = await poolOperator.createStakingPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
const revertError = new StakingRevertErrors.MakerAddressNotRegisteredError(
makerAddress,
stakingConstants.NIL_POOL_ID,
poolId,
);
// remove non-existent maker from pool
await poolOperator.removeMakerFromStakingPoolAsync(
poolId,
makerAddress,
RevertReason.MakerAddressNotRegistered,
revertError,
);
});
it('Should fail to add a maker who signed with the wrong private key', async () => {
@ -165,13 +171,18 @@ describe('Staking Pool Management', () => {
// create pool
const poolId = await poolOperator.createStakingPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
// add maker to poolxx
const makerApproval = maker.signApprovalForStakingPool(poolId);
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
poolId,
makerAddress,
makerApproval.signature,
);
await poolOperator.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
revertError,
);
});
it('Should fail to add a maker who signed with the wrong staking contract address', async () => {
@ -188,11 +199,16 @@ describe('Staking Pool Management', () => {
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
poolId,
makerAddress,
makerApproval.signature,
);
await poolOperator.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
revertError,
);
});
it('Should fail to add a maker who signed with the wrong chain id', async () => {
@ -216,11 +232,16 @@ describe('Staking Pool Management', () => {
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
poolId,
makerAddress,
makerApproval.signature,
);
await poolOperator.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
revertError,
);
});
it('Should fail to add a maker when called by someone other than the pool operator', async () => {
@ -236,15 +257,17 @@ describe('Staking Pool Management', () => {
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await expectTransactionFailedAsync(
stakingWrapper.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
notOperatorAddress,
),
RevertReason.OnlyCallableByPoolOperator,
const revertError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(
notOperatorAddress,
operatorAddress,
);
const tx = stakingWrapper.addMakerToStakingPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
notOperatorAddress,
);
await expect(tx).to.revertWith(revertError);
});
it('Should fail to remove a maker when called by someone other than the pool operator', async () => {
// test parameters
@ -261,10 +284,13 @@ describe('Staking Pool Management', () => {
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature);
// try to remove the maker address from an address other than the operator
await expectTransactionFailedAsync(
stakingWrapper.removeMakerFromStakingPoolAsync(poolId, makerAddress, notOperatorAddress),
RevertReason.OnlyCallableByPoolOperatorOrMaker,
const revertError = new StakingRevertErrors.OnlyCallableByPoolOperatorOrMakerError(
notOperatorAddress,
operatorAddress,
makerAddress,
);
const tx = stakingWrapper.removeMakerFromStakingPoolAsync(poolId, makerAddress, notOperatorAddress);
await expect(tx).to.revertWith(revertError);
});
});
});

View File

@ -1,14 +1,15 @@
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { Simulation } from './utils/Simulation';
import { StakingWrapper } from './utils/staking_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
// tslint:disable:no-unnecessary-type-assertion
describe('End-To-End Simulations', () => {
@ -348,10 +349,9 @@ describe('End-To-End Simulations', () => {
it('Should not be able to record a protocol fee from an unknown exchange', async () => {
const makerAddress = users[1];
const protocolFee = new BigNumber(1);
await expectTransactionFailedAsync(
stakingWrapper.payProtocolFeeAsync(makerAddress, protocolFee, owner),
RevertReason.OnlyCallableByExchange,
);
const revertError = new StakingRevertErrors.OnlyCallableByExchangeError(owner);
const tx = stakingWrapper.payProtocolFeeAsync(makerAddress, protocolFee, owner);
await expect(tx).to.revertWith(revertError);
});
});
});

View File

@ -2,7 +2,7 @@ import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
@ -66,9 +66,10 @@ describe('Staking & Delegating', () => {
await staker.deactivateAndTimeLockStakeAsync(amountToDeactivate);
// note - we cannot re-activate this timeLocked stake until at least one full timeLock period has passed.
// attempting to do so should revert.
await staker.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
const revertError = new StakingRevertErrors.InsufficientBalanceError(amountToReactivate, 0);
await staker.activateStakeAsync(amountToReactivate, revertError);
await staker.skipToNextTimeLockPeriodAsync();
await staker.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
await staker.activateStakeAsync(amountToReactivate, revertError);
await staker.skipToNextTimeLockPeriodAsync();
// this forces the internal state to update; it is not necessary to activate stake, but
// allows us to check that state is updated correctly after a timeLock period rolls over.
@ -95,9 +96,10 @@ describe('Staking & Delegating', () => {
await delegator.deactivateAndTimeLockDelegatedStakeAsync(poolId, amountToDeactivate);
// note - we cannot re-activate this timeLocked stake until at least one full timeLock period has passed.
// attempting to do so should revert.
await delegator.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
const revertError = new StakingRevertErrors.InsufficientBalanceError(amountToReactivate, 0);
await delegator.activateStakeAsync(amountToReactivate, revertError);
await delegator.skipToNextTimeLockPeriodAsync();
await delegator.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
await delegator.activateStakeAsync(amountToReactivate, revertError);
await delegator.skipToNextTimeLockPeriodAsync();
// this forces the internal state to update; it is not necessary to activate stake, but
// allows us to check that state is updated correctly after a timeLock period rolls over.

View File

@ -1,14 +1,15 @@
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { StakingWrapper } from './utils/staking_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
// tslint:disable:no-unnecessary-type-assertion
describe('Staking Vaults', () => {
@ -62,15 +63,13 @@ describe('Staking Vaults', () => {
// create pool in vault
await stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress);
// should fail to create pool if it already exists
await expectTransactionFailedAsync(
stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress),
RevertReason.PoolAlreadyExists,
);
let revertError = new StakingRevertErrors.PoolAlreadyExistsError(poolId);
let tx = stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress);
await expect(tx).to.revertWith(revertError);
// should fail to create a pool from an address other than the staking contract
await expectTransactionFailedAsync(
stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, notStakingContractAddress),
RevertReason.OnlyCallableByStakingContract,
);
revertError = new StakingRevertErrors.OnlyCallableByStakingContractError(notStakingContractAddress);
tx = stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, notStakingContractAddress);
await expect(tx).to.revertWith(revertError);
});
});
});

View File

@ -1,6 +1,7 @@
import * as ExchangeRevertErrors from './exchange_revert_errors';
import * as ForwarderRevertErrors from './forwarder_revert_errors';
import * as LibMathRevertErrors from './lib_math_revert_errors';
import * as StakingRevertErrors from './staking_revert_errors';
export { orderHashUtils } from './order_hash';
export { signatureUtils } from './signature_utils';
@ -86,4 +87,4 @@ export {
} from './types';
export { ExchangeContract, NetworkId } from '@0x/abi-gen-wrappers';
export { ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors };
export { ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors, StakingRevertErrors };