I have a contract that calls another contract using a try-catch, which reverts with a custom error. I am decoding the error reason bytes using abi.decode, but it is reverting when I try to decode.
This is using solidity 0.8.4 in remix.
The code is:
pragma solidity = 0.8.4;
error MyCustomError(uint256 value1, uint256 value2);
contract Reverter {
function revertMe(uint256 valueA, uint256 valueB) public {
revert MyCustomError(valueA, valueB);
}
}
contract RevertCaller {
Reverter reverter;
event Revert(uint256 indexed value1, uint256 indexed value2);
event LogBytes(bytes);
constructor() {
reverter = new Reverter();
}
function callRevert(uint256 valueA, uint256 valueB) public {
try reverter.revertMe(valueA, valueB) {
} catch (bytes memory reason) {
emit Revert(valueA, valueB);
emit LogBytes(reason);
(bytes4 errorSelector, uint256 value1, uint256 value2) = abi.decode(reason, (bytes4, uint256, uint256));
if (errorSelector == MyCustomError.selector) {
// Handle invalid amount error
emit Revert(value1, value2);
} else {
emit Revert(0, 0);
}
}
}
}
If I comment out the abi.decode line and pass some other values into the event, it does not revert. Also it works to only decoide the selector like this:
(bytes4 errorSelector) = abi.decode(reason, (bytes4));
but then I dont get the error args that I want to use.
The logged reason (using LogBytes) is 0x64f2b82800000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005
Maybe I am using abi.decode incorrectly?
You are indeed using
abi.decode
incorrectly.First 4 bytes of the error are treated the same way as the function selectors, and their encoding does not follow ABI specification. According to the ABI spec
bytes4
values should be padded with zeroes up to full 32 bytes. This is whyabi.decode(reason, (bytes4))
works, because of the following zeroes. However when you try to decode full bytes, there is not enough padding in the data for the decoder and it just reverts the transaction.Unfortunately there is still no good way to do custom error catching in solidity.
The following assembly code will achieve desired error matching behaviour:
For
bytes4 errorSelector = bytes4(reason)
casting to work you'll need to update to solidity 0.8.5.