Skip to content

Commit

Permalink
Merge pull request #5 from rhinestonewtf/feature/simulation-success
Browse files Browse the repository at this point in the history
feat: add simulation success return
  • Loading branch information
kopy-kat authored Aug 15, 2024
2 parents 68bdedc + 7675cdc commit e1e7c81
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 18 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rhinestone/erc4337-validation",
"version": "0.0.1-alpha.4",
"version": "0.0.1-alpha.5",
"description": "A library to validate the ERC-4337 rules within Foundry",
"license": "MIT",
"author": {
Expand Down
59 changes: 45 additions & 14 deletions src/Simulator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,47 @@ import { ERC4337SpecsParser } from "./SpecsParser.sol";
*/
library Simulator {
/**
* Simulates a UserOperation and validates the ERC-4337 rules will revert if the UserOperation
* is invalid
* Simulates a UserOperation and validates the ERC-4337 rules
* @dev This function will revert if the UserOperation is invalid
* @dev If the simulation fails, the rules might not be checked correctly so simulationSuccess
* should be handled accordingly
* @dev This function is used for v0.7 ERC-4337
*
* @param userOp The PackedUserOperation to simulate
* @param onEntryPoint The address of the entry point to simulate the UserOperation on
*
* @return simulationSuccess True if the simulation was successful, false otherwise
*/
function simulateUserOp(PackedUserOperation memory userOp, address onEntryPoint) internal {
function simulateUserOp(
PackedUserOperation memory userOp,
address onEntryPoint
)
internal
returns (bool simulationSuccess)
{
// Pre-simulation setup
_preSimulation();

// Simulate the UserOperation
// Encode the call data
bytes memory epCallData =
abi.encodeCall(IEntryPointSimulations.simulateValidation, (userOp));

// Simulate the UserOperation and exit on revert
bytes memory returnData;
(simulationSuccess, returnData) = address(onEntryPoint).call(epCallData);
if (!simulationSuccess) {
return simulationSuccess;
}

// Decode the return data
IEntryPointSimulations.ValidationResult memory result =
IEntryPointSimulations(onEntryPoint).simulateValidation(userOp);
abi.decode(returnData, (IEntryPointSimulations.ValidationResult));

// Ensure that the signature was valid
if (result.returnInfo.accountValidationData != 0) {
bool sigFailed = (result.returnInfo.accountValidationData & 1) == 1;
if (sigFailed) {
revert("Simulation error: signature failed");
simulationSuccess = false;
}
}

Expand All @@ -66,30 +87,40 @@ library Simulator {
}

/**
* Simulates a UserOperation and validates the ERC-4337 rules will revert if the UserOperation
* is invalid
* Simulates a UserOperation and validates the ERC-4337 rules
* @dev this function will revert if the UserOperation is invalid
* @dev If the simulation fails, the rules might not be checked correctly so simulationSuccess
* should be handled accordingly
* @dev This function is used for v0.6 ERC-4337
*
* @param userOp The UserOperation to simulate
* @param onEntryPoint The address of the entry point to simulate the UserOperation on
*
* @return simulationSuccess True if the simulation was successful, false otherwise
*/
function simulateUserOp(UserOperation memory userOp, address onEntryPoint) internal {
function simulateUserOp(
UserOperation memory userOp,
address onEntryPoint
)
internal
returns (bool simulationSuccess)
{
// Pre-simulation setup
_preSimulation();

// Simulate the UserOperation and handle revert
try IEntryPointSimulationsV060(onEntryPoint).simulateValidation(userOp) { }
catch (bytes memory reason) {
try IEntryPointSimulationsV060(onEntryPoint).simulateValidation(userOp) {
simulationSuccess = true;
} catch (bytes memory reason) {
simulationSuccess = false;

uint256 sigFailed;
// selector (4 bytes) + length(32 bytes) + preOpGas(32 bytes)
// + prefund (32 bytes) + sigFailed (32 bytes)
uint256 pos = 4 + 32 + 32 + 32;
assembly {

Check warning on line 121 in src/Simulator.sol

View workflow job for this annotation

GitHub Actions / lint / forge-lint

Avoid to use inline assembly. It is acceptable only in rare cases
sigFailed := mload(add(reason, pos))
}
if (sigFailed == 1) {
revert("Simulation error: signature failed");
}
}

// Create a UserOperationDetails struct
Expand Down
4 changes: 3 additions & 1 deletion src/SpecsParser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,9 @@ library ERC4337SpecsParser {
*
* @return entities The entities of the UserOperation
*/
function getEntities(UserOperationDetails memory userOpDetails)
function getEntities(
UserOperationDetails memory userOpDetails
)
internal
view
returns (Entities memory entities)
Expand Down
4 changes: 3 additions & 1 deletion test/utils/TestBaseUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ contract TestBaseUtil is Test {
factory = new MockFactory(address(implementation));
}

function getAccountAndInitCode(bytes32 salt)
function getAccountAndInitCode(
bytes32 salt
)
internal
returns (address account, bytes memory initCode)
{
Expand Down
4 changes: 3 additions & 1 deletion test/utils/TestBaseUtilV060.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ contract TestBaseUtil is Test {
factory = new MockFactory(address(implementation));
}

function getAccountAndInitCode(bytes32 salt)
function getAccountAndInitCode(
bytes32 salt
)
internal
returns (address account, bytes memory initCode)
{
Expand Down

0 comments on commit e1e7c81

Please sign in to comment.