diff --git a/src/test/ModuleKitHelpers.sol b/src/test/ModuleKitHelpers.sol index 886dd200..f49e091e 100644 --- a/src/test/ModuleKitHelpers.sol +++ b/src/test/ModuleKitHelpers.sol @@ -312,7 +312,15 @@ library ModuleKitHelpers { //////////////////////////////////////////////////////////////////////////*/ function expect4337Revert(AccountInstance memory) internal { - writeExpectRevert(1); + writeExpectRevert(""); + } + + function expect4337Revert(AccountInstance memory, bytes4 selector) internal { + writeExpectRevert(abi.encodePacked(selector)); + } + + function expect4337Revert(AccountInstance memory, bytes memory message) internal { + writeExpectRevert(message); } /** diff --git a/src/test/utils/ERC4337Helpers.sol b/src/test/utils/ERC4337Helpers.sol index 140680ff..af5d12d3 100644 --- a/src/test/utils/ERC4337Helpers.sol +++ b/src/test/utils/ERC4337Helpers.sol @@ -16,7 +16,8 @@ import { GasParser } from "./gas/GasParser.sol"; import { getSimulateUserOp, getExpectRevert, - writeExpectRevert, + getExpectRevertMessage, + clearExpectRevert, getGasIdentifier, writeGasIdentifier, writeInstalledModule, @@ -25,12 +26,16 @@ import { InstalledModule } from "./Storage.sol"; +import "forge-std/console2.sol"; + library ERC4337Helpers { using Simulator for PackedUserOperation; error UserOperationReverted( bytes32 userOpHash, address sender, uint256 nonce, bytes revertReason ); + error InvalidRevertMessage(bytes4 expected, bytes4 reason); + error InvalidRevertMessageBytes(bytes expected, bytes reason); function exec4337(PackedUserOperation[] memory userOps, IEntryPoint onEntryPoint) internal { uint256 isExpectRevert = getExpectRevert(); @@ -49,10 +54,12 @@ library ERC4337Helpers { // Execute userOps address payable beneficiary = payable(address(0x69)); bytes memory userOpCalldata = abi.encodeCall(IEntryPoint.handleOps, (userOps, beneficiary)); - (bool success,) = address(onEntryPoint).call(userOpCalldata); + (bool success, bytes memory returnData) = address(onEntryPoint).call(userOpCalldata); if (isExpectRevert == 0) { require(success, "UserOperation execution failed"); + } else if (isExpectRevert == 2 && !success) { + checkRevertMessage(returnData); } // Parse logs and determine if a revert happened @@ -75,7 +82,10 @@ library ERC4337Helpers { userOpHash, address(bytes20(logs[i].topics[2])), nonce, revertReason ); } else { - writeExpectRevert(0); + if (isExpectRevert == 2) { + checkRevertMessage(getUserOpRevertReason(logs, bytes32(0))); + } + clearExpectRevert(); } } } @@ -115,7 +125,7 @@ library ERC4337Helpers { require(!success, "UserOperation execution did not fail as expected"); } } - writeExpectRevert(0); + clearExpectRevert(); // Calculate gas for userOp string memory gasIdentifier = getGasIdentifier(); @@ -156,6 +166,24 @@ library ERC4337Helpers { } } + function checkRevertMessage(bytes memory actualReason) internal view { + bytes memory revertMessage = getExpectRevertMessage(); + console2.logBytes(revertMessage); + console2.logBytes(actualReason); + + if (revertMessage.length == 4) { + bytes4 expected = bytes4(revertMessage); + bytes4 actual = bytes4(actualReason); + if (expected != actual) { + revert InvalidRevertMessage(expected, actual); + } + } else { + if (revertMessage.length != actualReason.length) { + revert InvalidRevertMessageBytes(revertMessage, actualReason); + } + } + } + function calculateGas( PackedUserOperation[] memory userOps, IEntryPoint onEntryPoint, diff --git a/src/test/utils/Storage.sol b/src/test/utils/Storage.sol index 474677d8..3fd6cf02 100644 --- a/src/test/utils/Storage.sol +++ b/src/test/utils/Storage.sol @@ -5,8 +5,18 @@ pragma solidity ^0.8.23; EXPECT REVERT //////////////////////////////////////////////////////////////*/ -function writeExpectRevert(uint256 value) { - bytes32 slot = keccak256("ModuleKit.ExpectSlot"); +function writeExpectRevert(bytes memory message) { + uint256 value = 1; + bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); + + if (message.length > 0) { + value = 2; + assembly { + sstore(slot, message) + } + } + + slot = keccak256("ModuleKit.ExpectSlot"); assembly { sstore(slot, value) } @@ -19,6 +29,25 @@ function getExpectRevert() view returns (uint256 value) { } } +function getExpectRevertMessage() view returns (bytes memory data) { + bytes32 slot = keccak256("ModuleKit.ExpectMessageSlot"); + assembly { + data := sload(slot) + } +} + +function clearExpectRevert() { + bytes32 slot = keccak256("ModuleKit.ExpectSlot"); + assembly { + sstore(slot, 0) + } + + slot = keccak256("ModuleKit.ExpectMessageSlot"); + assembly { + sstore(slot, 0) + } +} + /*////////////////////////////////////////////////////////////// GAS IDENTIFIER //////////////////////////////////////////////////////////////*/ diff --git a/test/Diff.t.sol b/test/Diff.t.sol index 886f4523..f667a857 100644 --- a/test/Diff.t.sol +++ b/test/Diff.t.sol @@ -107,8 +107,14 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { _revertWhen__ValidationFails(""); // Revert selector + _revertWhen__ValidationReverts(abi.encodePacked(bytes4(0x65c8fd4d))); // Revert message + _revertWhen__ValidationReverts( + abi.encodeWithSignature( + "FailedOpWithRevert(uint256,string,bytes)", 0, "AA23 reverted", "" + ) + ); } function testexec__RevertWhen__ValidationReverts() public { @@ -116,6 +122,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { _revertWhen__ValidationReverts(""); // Revert selector + _revertWhen__ValidationReverts(abi.encodePacked(bytes4(hex"ffffffff"))); // Revert message } @@ -125,8 +132,12 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { _revertWhen__UserOperationFails(""); // Revert selector + _revertWhen__UserOperationFails(abi.encodePacked(bytes4(0x08c379a0))); // Revert message + _revertWhen__UserOperationFails( + abi.encodeWithSignature("Error(string)", "MockTarget: not authorized") + ); } /*////////////////////////////////////////////////////////////////////////// @@ -595,9 +606,9 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { if (revertReason.length == 0) { instance.expect4337Revert(); } else if (revertReason.length == 4) { - instance.expect4337Revert(); + instance.expect4337Revert(bytes4(revertReason)); } else { - instance.expect4337Revert(); + instance.expect4337Revert(revertReason); } // Create userOperation @@ -630,9 +641,9 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { if (revertReason.length == 0) { instance.expect4337Revert(); } else if (revertReason.length == 4) { - instance.expect4337Revert(); + instance.expect4337Revert(bytes4(revertReason)); } else { - instance.expect4337Revert(); + instance.expect4337Revert(revertReason); } // Create userOperation @@ -652,9 +663,9 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { if (revertReason.length == 0) { instance.expect4337Revert(); } else if (revertReason.length == 4) { - instance.expect4337Revert(); + instance.expect4337Revert(bytes4(revertReason)); } else { - instance.expect4337Revert(); + instance.expect4337Revert(revertReason); } // Create userOperation