Skip to content

Commit

Permalink
feat: use custom base account (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamegyed authored Sep 25, 2024
1 parent 69fac5e commit d855a70
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
177463
177441
2 changes: 1 addition & 1 deletion .forge-snapshots/ModularAccount_UserOp_Erc20Transfer.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193921
193896
2 changes: 1 addition & 1 deletion .forge-snapshots/ModularAccount_UserOp_NativeTransfer.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
169673
169648
Original file line number Diff line number Diff line change
@@ -1 +1 @@
186779
186754
Original file line number Diff line number Diff line change
@@ -1 +1 @@
162712
162687
54 changes: 54 additions & 0 deletions src/account/BaseAccount.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

/// @dev An optimized implementation of a base account contract for ERC-4337.
/// Provides a public view function for getting the EntryPoint address, but does not provide one for getting the
/// nonce. The nonce may be retrieved from the EntryPoint contract.
/// Implementing contracts should override the _validateUserOp function to provide account-specific validation
/// logic.
abstract contract BaseAccount is IAccount {
error NotEntryPoint();

/// @inheritdoc IAccount
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
virtual
override
returns (uint256 validationData)
{
_requireFromEntryPoint();

validationData = _validateUserOp(userOp, userOpHash);

// Pay the prefund if necessary.
// todo: storage-warming optimization if nonzero requiredPrefund
assembly ("memory-safe") {
if missingAccountFunds {
// Ignore failure (it's EntryPoint's job to verify, not the account's).
pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00))
}
}
}

/// @notice Get the EntryPoint address used by this account.
/// @return The EntryPoint address.
function entryPoint() public view virtual returns (IEntryPoint);

/// @notice Account-specific implementation of user op validation. Override this function to define the
/// account's validation logic.
function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
internal
virtual
returns (uint256 validationData);

/// @notice Revert if the sender is not the EntryPoint.
function _requireFromEntryPoint() internal view virtual {
if (msg.sender != address(entryPoint())) {
revert NotEntryPoint();
}
}
}
9 changes: 3 additions & 6 deletions src/account/ModularAccount.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import {BaseAccount} from "@eth-infinitism/account-abstraction/core/BaseAccount.sol";
import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
Expand Down Expand Up @@ -33,6 +32,7 @@ import {ValidationConfigLib} from "../libraries/ValidationConfigLib.sol";
import {AccountExecutor} from "./AccountExecutor.sol";
import {AccountStorage, getAccountStorage, toHookConfig, toSetValue} from "./AccountStorage.sol";
import {AccountStorageInitializable} from "./AccountStorageInitializable.sol";
import {BaseAccount} from "./BaseAccount.sol";
import {ModularAccountView} from "./ModularAccountView.sol";
import {ModuleManagerInternals} from "./ModuleManagerInternals.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
Expand Down Expand Up @@ -99,7 +99,6 @@ contract ModularAccount is

event DeferredInstallNonceInvalidated(uint256 nonce);

error NotEntryPoint();
error PostExecHookReverted(address module, uint32 entityId, bytes revertReason);
error PreExecHookReverted(address module, uint32 entityId, bytes revertReason);
error PreRuntimeValidationHookFailed(address module, uint32 entityId, bytes revertReason);
Expand Down Expand Up @@ -166,9 +165,7 @@ contract ModularAccount is
/// @notice Execution function that allows UO context to be passed to execution hooks
/// @dev This function is only callable by the EntryPoint
function executeUserOp(PackedUserOperation calldata userOp, bytes32) external override {
if (msg.sender != address(_ENTRY_POINT)) {
revert NotEntryPoint();
}
_requireFromEntryPoint();

ModuleEntity userOpValidationFunction = ModuleEntity.wrap(bytes24(userOp.signature[:24]));

Expand Down Expand Up @@ -365,7 +362,7 @@ contract ModularAccount is
// INTERNAL FUNCTIONS

// Parent function validateUserOp enforces that this call can only be made by the EntryPoint
function _validateSignature(PackedUserOperation calldata userOp, bytes32 userOpHash)
function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
internal
override
returns (uint256 validationData)
Expand Down

0 comments on commit d855a70

Please sign in to comment.