-
Notifications
You must be signed in to change notification settings - Fork 815
Add ERC: Enable Mode for modules in ERC-7579 accounts #1253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ernestognw
wants to merge
5
commits into
ethereum:master
Choose a base branch
from
ernestognw:erc/erc7579-enable-mode
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+248
−0
Open
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5d6f523
Draft: ERC-7579 Atomic Module installation
ernestognw 0aa0165
Draft: ERC-7579 Atomic Module installation
ernestognw 8934755
Update discussions and number
ernestognw 86944b4
up
ernestognw 0a512a5
Update to support multiple modules
ernestognw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,244 @@ | ||
| --- | ||
| eip: XXXX | ||
| title: Enable Mode for module installation in ERC-7579 Smart Accounts | ||
| description: Install and use ERC-7579 modules within a single user operation | ||
| author: Ernesto Garcia (@ernestognw), Taek Lee (@leekt) | ||
| discussions-to: TBD | ||
ernestognw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| status: Draft | ||
| type: Standards Track | ||
| category: ERC | ||
| created: 2025-10-02 | ||
| requires: 712, 1271, 4337, 7579 | ||
| --- | ||
|
|
||
| ## Abstract | ||
|
|
||
| This ERC defines a standard mechanism for [ERC-7579] compliant smart accounts to install and immediately use modules within a single user operation. The standard specifies a magic nonce prefix, signature encoding format, and [EIP-712] domain structure to authorize _enable mode_ to install the module during the validation phase of the user operation while maintaining security through account owner authorization. | ||
|
|
||
| [ERC-7579]: ./eip-7579.md | ||
| [EIP-712]: ./eip-712.md | ||
| [ERC-1271]: ./eip-1271.md | ||
| [ERC-4337]: ./eip-4337.md | ||
| [ERC-7579]: ./eip-7579.md | ||
|
|
||
| ## Motivation | ||
|
|
||
| Current [ERC-7579] implementations require separate transactions for module installation and usage, creating friction in user experience. Common use cases like session key modules and spending limit modules would benefit from _enable mode_ and immediate usage. | ||
|
|
||
| This standard addresses several key issues: | ||
|
|
||
| - **User Experience**: Reduces transaction count from 2+ to 1 for module installation and usage | ||
| - **Consistency across implementations**: Provides a standard pattern that works across different [ERC-7579] account implementations | ||
| - **Security**: Maintains strong authorization through [EIP-712] signatures from account owners | ||
|
|
||
| Real-world usage in production systems like Kernel has validated the need and feasibility of this pattern, particularly for session key management and dynamic module installation. | ||
|
|
||
| ## Specification | ||
|
|
||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. | ||
|
|
||
| ### Definitions | ||
|
|
||
| - **Enable Mode**: The logic branch triggered during the validation phase allowing to install and use an [ERC-7579] module within a single user operation | ||
| - **Installation Signature**: An [EIP-712] signature authorizing module installatio | ||
| - **User Operation Signature**: The signature for validating the user operation itself | ||
|
|
||
| ### Magic Nonce Prefix | ||
|
|
||
| Smart accounts implementing this standard MUST detect enable mode by checking for the magic prefix `0x01` in the most significant byte of the user operation nonce. | ||
|
|
||
| ```solidity | ||
| bytes1 constant ENABLE_MODE_PREFIX = 0x01; | ||
|
|
||
| bytes1 result; | ||
| uint256 nonce = userOp.nonce; | ||
| assembly ("memory-safe") { | ||
| result := and(nonce, shl(248, not(0))) | ||
| } | ||
| if (result == ENABLE_MODE_PREFIX) { | ||
| // Enter enable mode | ||
| } | ||
| ``` | ||
|
|
||
| ### Signature Encoding Format | ||
|
|
||
| When the enable mode prefix is detected, the user operation signature MUST be encoded as: | ||
|
|
||
| ```solidity | ||
| abi.encode( | ||
| uint256 moduleTypeId, | ||
| address module, | ||
| bytes initData, | ||
| bytes installationSignature, | ||
| bytes userOpSignature | ||
| ) | ||
| ``` | ||
|
|
||
| Where: | ||
|
|
||
| - `moduleTypeId`: The [ERC-7579] module type identifier | ||
| - `module`: The address of the module to install | ||
| - `initData`: Initialization data to pass to the module's `onInstall` function | ||
| - `installationSignature`: [EIP-712] signature authorizing the module installation | ||
| - `userOpSignature`: Signature for validating the user operation | ||
|
|
||
| ### EIP-712 Message Structure | ||
|
|
||
| The message structure MUST be: | ||
|
|
||
| ```solidity | ||
| bytes32 constant ENABLE_MODULE_TYPEHASH = keccak256( | ||
| "EnableAtomicModule(uint256 moduleTypeId,address module,bytes initData,uint256 nonce)" | ||
| ); | ||
| ``` | ||
|
|
||
| ### Validation Flow | ||
|
|
||
| Smart accounts implementing this standard on top of [ERC-4337]'s `validateUserOp` function: | ||
|
|
||
| 1. MUST detect the enable mode prefix (`0x01`) in user operation nonces | ||
| 2. MUST decode the signature according to the specified format | ||
| 3. MUST validate the EIP-712 `installationSignature` using `isValidSignature` | ||
| 4. SHOULD install the module using the standard ERC-7579 `installModule` flow using the `moduleTypeId`, `module`, and `initData` | ||
| 5. MUST continue with normal user operation validation using the extracted `userOpSignature` | ||
| 6. MUST return `SIG_VALIDATION_FAILED` (`1`) if signature decoding fails or enabling signature is invalid | ||
|
|
||
| ## Rationale | ||
|
|
||
| ### Magic Nonce Prefix Choice | ||
|
|
||
| The prefix `0x01` was chosen because: | ||
|
|
||
| - It's unlikely to conflict with existing nonce usage patterns | ||
| - It's easily detectable with bitwise operations | ||
| - It follows the pattern established by successful implementations like Kernel | ||
|
|
||
| ### Signature Structure Design | ||
|
|
||
| The signature encoding separates concerns cleanly: | ||
|
|
||
| - Module installation data is explicitly structured | ||
| - Installation authorization is separate from user operation validation | ||
| - The format is extensible for future enhancements | ||
|
|
||
| ### EIP-712 Integration | ||
|
|
||
| Using EIP-712 for installation authorization provides: | ||
|
|
||
| - Strong cryptographic guarantees | ||
| - Human-readable signature requests in wallets | ||
| - Standard domain separation | ||
| - Replay protection through nonce inclusion | ||
|
|
||
| ### Compatibility with ERC-7579 | ||
|
|
||
| This standard extends ERC-7579 without breaking existing functionality: | ||
|
|
||
| - Normal user operations continue to work unchanged | ||
| - Standard module installation flows remain available | ||
| - All ERC-7579 security guarantees are preserved | ||
|
|
||
| ## Backwards Compatibility | ||
|
|
||
| This standard is fully backwards compatible with existing ERC-7579 implementations: | ||
|
|
||
| - Accounts not implementing this standard ignore the magic nonce prefix | ||
| - Standard module installation methods remain unchanged | ||
| - Existing modules work without modification | ||
| - User operations without the magic prefix function normally | ||
|
|
||
| ## Reference Implementation | ||
|
|
||
| ```solidity | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.27; | ||
|
|
||
| import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol"; | ||
| import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol"; | ||
| import {ERC4337Utils} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol"; | ||
| import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; | ||
|
|
||
| abstract contract EnableModeAccount is AccountERC7579, ... { | ||
| bytes1 private constant ENABLE_MODE_PREFIX = 0x01; | ||
| bytes32 private constant ENABLE_MODULE_TYPEHASH = | ||
| keccak256( | ||
| "EnableAtomicModule(uint256 moduleTypeId,address module,bytes initData,uint256 nonce)" | ||
| ); | ||
|
|
||
| function _validateUserOp( | ||
| PackedUserOperation calldata userOp, | ||
| bytes32 userOpHash | ||
| ) internal virtual override returns (uint256) { | ||
| bytes1 result; | ||
| uint256 nonce = userOp.nonce; | ||
| assembly ("memory-safe") { | ||
| result := and(nonce, shl(248, not(0))) | ||
| } | ||
| if (result == ENABLE_MODE_PREFIX) { | ||
| return _validateEnableMode(userOp, userOpHash); | ||
| } | ||
| return super._validateUserOp(userOp, userOpHash); | ||
| } | ||
|
|
||
| function _validateEnableMode( | ||
| PackedUserOperation calldata userOp, | ||
| bytes32 userOpHash | ||
| ) internal returns (uint256) { | ||
| ( | ||
| bool success, | ||
| uint256 moduleTypeId, | ||
| address module, | ||
| bytes calldata initData, | ||
| bytes calldata installationSignature, | ||
| bytes calldata userOpSignature | ||
| ) = _tryDecodeEnableMode(userOp.signature); | ||
|
|
||
| if (!success) { | ||
| return ERC4337Utils.SIG_VALIDATION_FAILED; | ||
| } | ||
|
|
||
| bytes32 structHash = _installModuleStructHash( | ||
| moduleTypeId, | ||
| module, | ||
| initData, | ||
| userOp.nonce | ||
| ); | ||
|
|
||
| if ( | ||
| isValidSignature(_hashTypedDataV4(structHash), installationSignature) == | ||
| IERC1271.isValidSignature.selector | ||
| ) { | ||
| _installModule(moduleTypeId, module, initData); | ||
|
|
||
| // Create modified userOp with extracted signature | ||
| PackedUserOperation memory modifiedUserOp = PackedUserOperation({ | ||
| sender: userOp.sender, | ||
| nonce: userOp.nonce, | ||
| initCode: userOp.initCode, | ||
| callData: userOp.callData, | ||
| accountGasLimits: userOp.accountGasLimits, | ||
| preVerificationGas: userOp.preVerificationGas, | ||
| gasFees: userOp.gasFees, | ||
| paymasterAndData: userOp.paymasterAndData, | ||
| signature: userOpSignature | ||
| }); | ||
|
|
||
| return super._validateUserOp(modifiedUserOp, userOpHash); | ||
| } | ||
|
|
||
| return ERC4337Utils.SIG_VALIDATION_FAILED; | ||
| } | ||
|
|
||
| // Additional implementation methods... | ||
| } | ||
| ``` | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| - **Authorization**: Only _account owners_ can authorize module installation through EIP-712 signatures | ||
| - **Replay Protection**: Nonce inclusion in EIP-712 message prevents replay attacks | ||
| - **Module Validation**: Standard ERC-7579 module validation applies (type checking, duplicate prevention) | ||
|
|
||
| ## Copyright | ||
|
|
||
| Copyright and related rights waived via [CC0](../LICENSE.md). | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.