Modular accounts with ERC-7579
ERC-7579 defines an interface for modular smart accounts
Introduction
ERC-7579 outlines interfaces and behavior for modular smart accounts to ensure interoperability. It was developed by Rhinestone, ZeroDev, Biconomy, and OKX from their experiences developing with ERC-6900.
Read the standard at ethereum.org ↗
ERC-7579 accounts can only be used with the v0.7 EntryPoint, which is not yet supported by all providers.
Reference Implementation
The reference implementation of ERC-7579 is the best place to start developing a custom smart account. It includes two accounts:
- MSABasic, which contains the minimal interface
- MSAAdvanced, which has an optional hook extension
In most cases you will want to use the MSABasic account.
Account interface
ERC-7579 smart accounts are ERC-4337 compliant smart contract accounts with a modular architecture. An account has three functions: accountId
, supportsAccountMode
, and supportsModule
.
The accountId
can be used to identify an account, which is useful for determining the account type and version.
supportsAccountMode
returns if the account supports an execution mode.
supportsModule
returns if the account supports a module type.
Execution
Smart accounts using this standard have two execution functions: execute
and executeFromExecutor
. These allow the user to define an execution mode
. It can optionally have an executeUserOp
function.
execute
execute
This function is intended to be called by the EntryPoint.
function execute(bytes32 mode, bytes calldata executionCalldata) external payable;
executeFromExecutor
executeFromExecutor
This function is intended to be called only by executor modules.
function executeFromExecutor(bytes32 mode, bytes calldata executionCalldata)
external
payable
returns (bytes[] memory returnData);
executeUserOp
executeUserOp
This optional function is like execute
, but allows an entire packed user operation to be passed.
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external payable;
Execution Modes
The execution mode is a bytes32 value that is structured as follows:
- callType (1 byte): 0x00 for a single call, 0x01 for a batch call and 0xff for delegatecall
- execType (1 byte): 0x00 for executions that revert on failure, 0x01 for executions that do not revert on failure but implement some form of error handling
- unused (4 bytes): this range is reserved for future standardization
- modeSelector (4 bytes): an additional mode selector that can be used to create further execution modes
- modePayload (22 bytes): additional data to be passed
The account has a supportsAccountMode
function that checks if the mode is supported.
Modules
There are four types of modules: validators, executors, fallback handlers, and hooks.
- Validators: A module used during the ERC-4337 validation flow to determine if a
PackedUserOperation
is valid. - Executors: A module that can execute transactions on behalf of the smart account via a callback.
- Fallback Handlers: A module that can extend the fallback functionality of a smart account.
- Hooks: An optional module that can execute custom logic before and after execution.
Smart accounts using this standard have three functions and two events related to modules.
installModule
is a function that installs a module by calling theonInstall
function on a module. It emits aModuleInstalled
event.uninstallModule
is a function that uninstalls a module by calling theonUninstall
function on the module. It emits aModuleUninstalled
event.isModuleInstalled
returns if a given module is installed.
These functions require the type of module to be specified: 1
for validators, 2
for executors, 3
for fallback handlers, and 4
for hooks.
Module contracts
Each module smart contract will have four functions:
onInstall
is a function that executes call data to install the moduleonUninstall
is a function that executes call data to uninstall the moduleisModuleType
is a function that returns true of a module is of the given typegetModuleType
is a function that returns the different TypeIds of the module.
Validator Modules
In addition to the standard module interface, validators have a validateUserOp
function and an isValidSignatureWithSender
function.
interface IValidator is IModule {
/**
* @dev Validates a UserOperation
* @param userOp the ERC-4337 PackedUserOperation
* @param userOpHash the hash of the ERC-4337 PackedUserOperation
*
* MUST validate that the signature is a valid signature of the userOpHash
* SHOULD return ERC-4337's SIG_VALIDATION_FAILED (and not revert) on signature mismatch
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256);
/**
* @dev Validates a signature using ERC-1271
* @param sender the address that sent the ERC-1271 request to the smart account
* @param hash the hash of the ERC-1271 request
* @param signature the signature of the ERC-1271 request
*
* MUST return the ERC-1271 `MAGIC_VALUE` if the signature is valid
* MUST NOT modify state
*/
function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature) external view returns (bytes4);
}
Executors
Executors are not required to have any interface other than the standard module interface.
Fallback Handlers
Fallback Handlers also do not require any interface other than the standard module interface.
Hooks
In addition to the standard module interface, hooks have a preCheck
and postCheck
function.
interface IHook is IModule {
/**
* @dev Called by the smart account before execution
* @param msgSender the address that called the smart account
* @param msgData the data that was sent to the smart account
*
* MAY return arbitrary data in the `hookData` return value
*/
function preCheck(address msgSender, bytes calldata msgData) external returns (bytes memory hookData);
/**
* @dev Called by the smart account after execution
* @param hookData the data that was returned by the `preCheck` function
*
* MAY validate the `hookData` to validate transaction context of the `preCheck` function
*/
function postCheck(bytes calldata hookData) external returns (bool success);
}
Updated 9 months ago