Merge pull request #2668 from 0xProject/improvement/nested-revert-decoding
`@0x/utils`: Add support for nested rich revert decoding
This commit is contained in:
commit
458a014e6d
@ -286,11 +286,11 @@ describe('AssetProxyDispatcher', () => {
|
||||
});
|
||||
const encodedAssetData = encodeERC20AssetData(erc20TokenA.address);
|
||||
const amount = new BigNumber(1);
|
||||
const nestedError = new StringRevertError(RevertReason.TransferFailed).encode();
|
||||
const nestedError = new StringRevertError(RevertReason.TransferFailed);
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHash,
|
||||
encodedAssetData,
|
||||
nestedError,
|
||||
nestedError.toString(),
|
||||
);
|
||||
const tx = assetProxyDispatcher
|
||||
.dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount)
|
||||
@ -309,11 +309,11 @@ describe('AssetProxyDispatcher', () => {
|
||||
from: makerAddress,
|
||||
});
|
||||
const transferIndexAsBytes32 = '0x0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const nestedError = new StringRevertError(RevertReason.TransferFailed).encode();
|
||||
const nestedError = new StringRevertError(RevertReason.TransferFailed);
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
transferIndexAsBytes32,
|
||||
assetDataB,
|
||||
nestedError,
|
||||
nestedError.toString(),
|
||||
);
|
||||
const tx = assetProxyDispatcher
|
||||
.simulateDispatchTransferFromCalls(
|
||||
|
@ -300,7 +300,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
new StringRevertError(validatorWalletRevertReason).toString(),
|
||||
);
|
||||
const tx = validateAsync(hashHex, validatorWallet.address, signatureHex, ValidatorWalletAction.Revert);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
@ -562,7 +562,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
validatorWallet.address,
|
||||
data,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
new StringRevertError(validatorWalletRevertReason).toString(),
|
||||
);
|
||||
const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.Revert);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
@ -693,7 +693,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
validatorWallet.address,
|
||||
data,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
new StringRevertError(validatorWalletRevertReason).toString(),
|
||||
);
|
||||
const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.Revert);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
@ -916,7 +916,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
validatorWallet.address,
|
||||
data,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
new StringRevertError(validatorWalletRevertReason).toString(),
|
||||
);
|
||||
const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.Revert);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
@ -1041,7 +1041,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
validatorWallet.address,
|
||||
data,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
new StringRevertError(validatorWalletRevertReason).toString(),
|
||||
);
|
||||
const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.Revert);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
|
@ -101,7 +101,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
executableError.toString(),
|
||||
);
|
||||
|
||||
// Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error.
|
||||
@ -123,7 +123,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
executableError.toString(),
|
||||
);
|
||||
|
||||
// Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error.
|
||||
@ -145,7 +145,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
executableError.toString(),
|
||||
);
|
||||
|
||||
// Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error.
|
||||
@ -280,7 +280,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const outerExecuteTransactionHash = transactionHashUtils.getTransactionHashHex(outerExecuteTransaction);
|
||||
const outerExpectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
outerExecuteTransactionHash,
|
||||
innerExpectedError.encode(),
|
||||
innerExpectedError.toString(),
|
||||
);
|
||||
const tx = transactionsContract
|
||||
.batchExecuteTransactions([outerExecuteTransaction], [randomSignature()])
|
||||
@ -363,7 +363,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const errorData = new ExchangeRevertErrors.TransactionInvalidContextError(
|
||||
innerTransactionHash,
|
||||
accounts[0],
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(outerTransactionHash, errorData);
|
||||
const tx = transactionsContract
|
||||
.executeTransaction(outerTransaction, validSignature)
|
||||
@ -385,7 +385,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const errorData = new ExchangeRevertErrors.TransactionInvalidContextError(
|
||||
innerTransactionHash,
|
||||
accounts[0],
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(outerTransactionHash, errorData);
|
||||
const tx = transactionsContract
|
||||
.executeTransaction(outerTransaction, validSignature)
|
||||
@ -466,7 +466,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
executableError.toString(),
|
||||
);
|
||||
const tx = transactionsContract
|
||||
.executeTransaction(transaction, randomSignature())
|
||||
@ -486,7 +486,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
executableError.toString(),
|
||||
);
|
||||
const tx = transactionsContract
|
||||
.executeTransaction(transaction, validSignature)
|
||||
|
@ -558,7 +558,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
signedOrder.makerAssetData,
|
||||
new StringRevertError(RevertReason.TransferFailed).encode(),
|
||||
new StringRevertError(RevertReason.TransferFailed).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature)
|
||||
@ -587,7 +587,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
signedOrder.takerAssetData,
|
||||
new StringRevertError(RevertReason.TransferFailed).encode(),
|
||||
new StringRevertError(RevertReason.TransferFailed).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature)
|
||||
@ -616,7 +616,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
signedOrder.makerAssetData,
|
||||
new StringRevertError(RevertReason.InvalidAmount).encode(),
|
||||
new StringRevertError(RevertReason.InvalidAmount).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature)
|
||||
@ -645,7 +645,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
signedOrder.takerAssetData,
|
||||
new StringRevertError(RevertReason.InvalidAmount).encode(),
|
||||
new StringRevertError(RevertReason.InvalidAmount).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature)
|
||||
@ -980,7 +980,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
assetData,
|
||||
new StringRevertError(RevertReason.TargetNotEven).encode(),
|
||||
new StringRevertError(RevertReason.TargetNotEven).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature)
|
||||
@ -1015,7 +1015,7 @@ blockchainTests.resets('Exchange core', () => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashHex,
|
||||
assetData,
|
||||
new StringRevertError(RevertReason.TargetNotEven).encode(),
|
||||
new StringRevertError(RevertReason.TargetNotEven).toString(),
|
||||
);
|
||||
const tx = exchange
|
||||
.fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature)
|
||||
|
@ -9,7 +9,7 @@ import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { LibMathRevertErrors } from '@0x/contracts-exchange-libs';
|
||||
import { blockchainTests, constants, describe, expect, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { SignedOrder } from '@0x/order-utils';
|
||||
import { BigNumber, RevertError } from '@0x/utils';
|
||||
import { BigNumber, decodeThrownErrorAsRevertError, StringRevertError } from '@0x/utils';
|
||||
import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@ -276,9 +276,9 @@ blockchainTests.resets('Exchange fills dydx orders', env => {
|
||||
try {
|
||||
await txPromise.catch();
|
||||
} catch (e) {
|
||||
assetProxyError = RevertError.decode(e.values.errorData);
|
||||
assetProxyError = decodeThrownErrorAsRevertError(e).values.errorData;
|
||||
}
|
||||
expect(assetProxyError).to.deep.equal(expectedAssetProxyError);
|
||||
expect(assetProxyError).to.deep.equal(new StringRevertError(expectedAssetProxyError.toString()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -121,7 +121,7 @@ blockchainTests.resets('Transaction <> protocol fee integration tests', env => {
|
||||
maker.address,
|
||||
wethless.address,
|
||||
'0x',
|
||||
).encode();
|
||||
).toString();
|
||||
return new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(failedTransaction),
|
||||
nestedError,
|
||||
@ -252,7 +252,7 @@ blockchainTests.resets('Transaction <> protocol fee integration tests', env => {
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(recursiveTransaction),
|
||||
protocolFeeError(order, transaction).encode(),
|
||||
protocolFeeError(order, transaction).toString(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
@ -280,7 +280,7 @@ blockchainTests.resets('Transaction integration tests', env => {
|
||||
const noReentrancyError = new ExchangeRevertErrors.TransactionInvalidContextError(
|
||||
transactionHashHex,
|
||||
transaction.signerAddress,
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
recursiveTransactionHashHex,
|
||||
noReentrancyError,
|
||||
@ -330,7 +330,7 @@ blockchainTests.resets('Transaction integration tests', env => {
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAddress,
|
||||
order.signature,
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
@ -353,7 +353,7 @@ blockchainTests.resets('Transaction integration tests', env => {
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
takers[0].address,
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
@ -403,7 +403,7 @@ blockchainTests.resets('Transaction integration tests', env => {
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(orders[0]),
|
||||
takers[0].address,
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
@ -771,7 +771,7 @@ blockchainTests.resets('Transaction integration tests', env => {
|
||||
const nestedError = new ExchangeRevertErrors.OrderStatusError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
OrderStatus.Cancelled,
|
||||
).encode();
|
||||
).toString();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
nestedError,
|
||||
|
@ -123,7 +123,7 @@ blockchainTests.resets('Chainlink stop-limit order tests', env => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAssetData,
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').toString(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
@ -133,7 +133,7 @@ blockchainTests.resets('Chainlink stop-limit order tests', env => {
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAssetData,
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').toString(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
@ -297,7 +297,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError(
|
||||
mtxHash,
|
||||
actualCallData,
|
||||
new StringRevertError('FAIL').encode(),
|
||||
new StringRevertError('FAIL').toString(),
|
||||
),
|
||||
);
|
||||
});
|
||||
@ -465,7 +465,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
mtxHash,
|
||||
signers[0],
|
||||
signature,
|
||||
).encode(),
|
||||
).toString(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -102,7 +102,7 @@ blockchainTests.resets('Ownable feature', env => {
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.Ownable.MigrateCallFailedError(
|
||||
testMigrator.address,
|
||||
new StringRevertError('OOPSIE').encode(),
|
||||
new StringRevertError('OOPSIE').toString(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ blockchainTests.resets('TokenSpender feature', env => {
|
||||
tokenFrom,
|
||||
tokenTo,
|
||||
tokenAmount,
|
||||
new StringRevertError('TestTokenSpenderERC20Token/Revert').encode(),
|
||||
new StringRevertError('TestTokenSpenderERC20Token/Revert').toString(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
@ -127,7 +127,7 @@ blockchainTests.resets('FlashWallet', env => {
|
||||
callTarget.address,
|
||||
REVERTING_DATA,
|
||||
constants.ZERO_AMOUNT,
|
||||
new StringRevertError('TestCallTarget/REVERT').encode(),
|
||||
new StringRevertError('TestCallTarget/REVERT').toString(),
|
||||
),
|
||||
);
|
||||
});
|
||||
@ -203,7 +203,7 @@ blockchainTests.resets('FlashWallet', env => {
|
||||
wallet.address,
|
||||
callTarget.address,
|
||||
REVERTING_DATA,
|
||||
new StringRevertError('TestCallTarget/REVERT').encode(),
|
||||
new StringRevertError('TestCallTarget/REVERT').toString(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "5.6.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added support for nested rich revert decoding",
|
||||
"pr": 2668
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "5.5.1",
|
||||
|
@ -14,6 +14,7 @@ type ArgTypes =
|
||||
| BigNumber
|
||||
| number
|
||||
| boolean
|
||||
| RevertError
|
||||
| BigNumber[]
|
||||
| string[]
|
||||
| number[]
|
||||
@ -122,6 +123,19 @@ export abstract class RevertError extends Error {
|
||||
const instance = new type();
|
||||
try {
|
||||
const values = decoder(_bytes);
|
||||
_.transform(
|
||||
values,
|
||||
(result, value, key) => {
|
||||
const { type: argType } = instance._getArgumentByName(key);
|
||||
if (argType === 'bytes') {
|
||||
try {
|
||||
const nestedRevert = RevertError.decode(value as string, coerce);
|
||||
result[key] = nestedRevert.toString();
|
||||
} catch (err) {} // tslint:disable-line:no-empty
|
||||
}
|
||||
},
|
||||
values,
|
||||
);
|
||||
_.assign(instance, { values });
|
||||
instance.message = instance.toString();
|
||||
return instance;
|
||||
|
@ -39,7 +39,14 @@ class FixedSizeArrayRevertError extends RevertError {
|
||||
}
|
||||
}
|
||||
|
||||
class ParentRevertError extends RevertError {
|
||||
public constructor(nestedError?: string) {
|
||||
super('ParentRevertError', 'ParentRevertError(bytes nestedError)', { nestedError });
|
||||
}
|
||||
}
|
||||
|
||||
RevertError.registerType(CustomRevertError);
|
||||
RevertError.registerType(ParentRevertError);
|
||||
|
||||
describe('RevertError', () => {
|
||||
describe('equality', () => {
|
||||
@ -159,6 +166,12 @@ describe('RevertError', () => {
|
||||
const decode = () => RevertError.decode(_encoded);
|
||||
expect(decode).to.throw();
|
||||
});
|
||||
it('should decode a nested revert error', () => {
|
||||
const nested = new StringRevertError(message);
|
||||
const parent = new ParentRevertError(nested.encode());
|
||||
const decoded = RevertError.decode(parent.encode());
|
||||
expect(decoded.toString()).to.equal(new ParentRevertError(nested.toString()).toString());
|
||||
});
|
||||
});
|
||||
describe('getThrownErrorRevertErrorBytes', () => {
|
||||
it('should decode Parity revert errors', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user