Skip to content

Commit

Permalink
Merge pull request #178 from rhinestonewtf/feat/return-exec-logs
Browse files Browse the repository at this point in the history
feat(ERC4337Helpers): return logs from exec4337
  • Loading branch information
kopy-kat authored Jan 10, 2025
2 parents 5d6590a + 59e1c98 commit dc865c7
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 7 deletions.
14 changes: 11 additions & 3 deletions src/test/ModuleKitHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity >=0.8.23 <0.9.0;
import {
AccountInstance,
UserOpData,
ExecutionReturnData,
AccountType,
DEFAULT,
SAFE,
Expand Down Expand Up @@ -41,7 +42,8 @@ import {
startStateDiffRecording as vmStartStateDiffRecording,
stopAndReturnStateDiff as vmStopAndReturnStateDiff,
getMappingKeyAndParentOf,
envOr
envOr,
setEnv
} from "./utils/Vm.sol";
import {
getAccountType as getAccountTypeFromStorage,
Expand Down Expand Up @@ -94,9 +96,13 @@ library ModuleKitHelpers {

/// @notice Executes userOps on the entrypoint
/// @param userOpData UserOpData struct containing the userOp, userOpHash, and entrypoint
function execUserOps(UserOpData memory userOpData) internal {
/// @return ExecutionReturnData struct containing the logs from the execution
function execUserOps(UserOpData memory userOpData)
internal
returns (ExecutionReturnData memory)
{
// Send userOp to entrypoint
ERC4337Helpers.exec4337(userOpData.userOp, userOpData.entrypoint);
return ERC4337Helpers.exec4337(userOpData.userOp, userOpData.entrypoint);
}

/// @notice Configures a userOp to execute a single operation
Expand Down Expand Up @@ -556,6 +562,8 @@ library ModuleKitHelpers {
/// @param value The value to write to storage (true or false)
function simulateUserOp(AccountInstance memory, bool value) internal {
writeSimulateUserOp(value);
string memory strValue = value ? "true" : "false";
setEnv("SIMULATE", strValue);
}

/// @notice Writes the storage compliance flag to storage
Expand Down
6 changes: 6 additions & 0 deletions src/test/RhinestoneModuleKit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ struct UserOpData {
IEntryPoint entrypoint;
}

/// @title ExecutionReturnData
/// @param logs Execution logs
struct ExecutionReturnData {
VmSafe.Log[] logs;
}

/// @title RhinestoneModuleKit
/// @notice A development kit for building and testing smart account modules
contract RhinestoneModuleKit is AuxiliaryFactory {
Expand Down
20 changes: 17 additions & 3 deletions src/test/utils/ERC4337Helpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
IEntryPointSimulations,
IStakeManager
} from "../../external/ERC4337.sol";
import { ExecutionReturnData } from "../RhinestoneModuleKit.sol";

// Deployments
import { ENTRYPOINT_ADDR } from "../../deployment/predeploy/EntryPoint.sol";
Expand Down Expand Up @@ -45,7 +46,13 @@ library ERC4337Helpers {
error InvalidRevertMessage(bytes4 expected, bytes4 reason);
error InvalidRevertMessageBytes(bytes expected, bytes reason);

function exec4337(PackedUserOperation[] memory userOps, IEntryPoint onEntryPoint) internal {
function exec4337(
PackedUserOperation[] memory userOps,
IEntryPoint onEntryPoint
)
internal
returns (ExecutionReturnData memory executionData)
{
uint256 isExpectRevert = getExpectRevert();

// ERC-4337 specs validation
Expand All @@ -72,6 +79,7 @@ library ERC4337Helpers {

// Parse logs and determine if a revert happened
VmSafe.Log[] memory logs = getRecordedLogs();
executionData = ExecutionReturnData(logs);
uint256 totalUserOpGas = 0;
for (uint256 i; i < logs.length; i++) {
// UserOperationEvent(bytes32,address,address,uint256,bool,uint256,uint256)
Expand Down Expand Up @@ -150,10 +158,16 @@ library ERC4337Helpers {
}
}

function exec4337(PackedUserOperation memory userOp, IEntryPoint onEntryPoint) internal {
function exec4337(
PackedUserOperation memory userOp,
IEntryPoint onEntryPoint
)
internal
returns (ExecutionReturnData memory logs)
{
PackedUserOperation[] memory userOps = new PackedUserOperation[](1);
userOps[0] = userOp;
exec4337(userOps, onEntryPoint);
return exec4337(userOps, onEntryPoint);
}

function getUserOpRevertReason(
Expand Down
4 changes: 4 additions & 0 deletions src/test/utils/Vm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ function envOr(string memory name, bool defaultValue) view returns (bool value)
return Vm(VM_ADDR).envOr(name, defaultValue);
}

function setEnv(string memory key, string memory value) {
Vm(VM_ADDR).setEnv(key, value);
}

function envBool(string memory key) view returns (bool value) {
return Vm(VM_ADDR).envBool(key);
}
Expand Down
7 changes: 6 additions & 1 deletion test/Diff.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity >=0.8.23 <0.9.0;
import "src/ModuleKit.sol";
import "./BaseTest.t.sol";
import "src/Mocks.sol";
import { ExecutionReturnData } from "src/test/RhinestoneModuleKit.sol";
import {
MODULE_TYPE_VALIDATOR,
MODULE_TYPE_EXECUTOR,
Expand Down Expand Up @@ -52,6 +53,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest {
token.initialize("Mock Token", "MTK", 18);
deal(address(token), instance.account, 100 ether);
vm.deal(instance.account, 1000 ether);
instance.simulateUserOp(false);
}

function test_transfer() public {
Expand Down Expand Up @@ -100,13 +102,16 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest {
// bytes memory signature = "";

// Create userOperation
instance.getExecOps({
ExecutionReturnData memory executionData = instance.getExecOps({
target: receiver,
value: value,
callData: callData,
txValidator: address(instance.defaultValidator)
}).execUserOps();

// Validate Logs
assertTrue(executionData.logs.length >= 5);

// Validate userOperation
assertEq(receiver.balance, value, "Receiver should have 10 gwei");
}
Expand Down
1 change: 1 addition & 0 deletions test/integrations/SwapTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ contract TestUniswap is BaseTest {
_fundAccountWithTokenA(amountIn);
vm.deal(instance.account, 1 ether);
assertTrue(instance.account.balance == 1 ether);
instance.simulateUserOp(false);
}

function _fundAccountWithTokenA(uint256 amount) internal {
Expand Down

0 comments on commit dc865c7

Please sign in to comment.