β 05 - RevertWithSelectorPlusArgs
Goal: Revert with a custom error that includes argument data.
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {RevertWithSelectorPlusArgs} from "../src/RevertWithSelectorPlusArgs.sol";
contract RevertWithSelectorPlusArgsTest is Test {
RevertWithSelectorPlusArgs public c;
function setUp() public {
c = new RevertWithSelectorPlusArgs();
}
function test_RevertWithSelectorPlusArgs(uint256 x) public {
vm.expectRevert(abi.encodeWithSelector(RevertWithSelectorPlusArgs.RevertData.selector, x));
c.main(x);
}
}
The idea is the same as previous level and this one is easier: the argument x
is a static type instead of dynamic type, so we donβt worry about ABI encoding (offset + length + data format).
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.13;
contract RevertWithSelectorPlusArgs {
error RevertData(uint256); // selector: 0xae412287
function main(uint256 x) external pure {
assembly {
// Allocate a free memory pointer
let ptr := mload(0x40)
// Write the error selector in the first 4 bytes.
// Use shl(224, 0xae412287) to shift the 4-byte selector into the high order position.
mstore(ptr, shl(224, 0xae412287))
// Write the argument "x" immediately after the selector.
mstore(add(ptr, 4), x)
// Revert with the custom error message consisting of 36 bytes: 4 for the selector and 32 for "x".
revert(ptr, 36)
}
}
}
Explanation:
We obtain a pointer to free memory via
mload(0x40)
.The error selector for
RevertData(uint256)
is0xae412287
. We shift it left by 224 bits (32 bytes - 4 bytes = 28 bytes; 28 * 8 = 224 bits) so that it occupies the high-order 4 bytes of a 32-byte word.The parameter
x
is stored immediately after the selector, at memory locationptr + 4
.Finally, we call
revert(ptr, 36)
to trigger a revert with 36 bytes of error data (4 bytes of selector + 32 bytes for the encoded uint256).
Run test:
forge test --mp test/RevertWithSelectorPlusArgs.t.sol -vvvv

Last updated