Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 248 additions & 0 deletions ERCS/erc-8043.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
---
eip: 8043
title: Enable Mode for modules in ERC-7579 accounts
description: Install and use ERC-7579 modules within a single user operation
author: Ernesto Garcia (@ernestognw), Taek Lee (@leekt)
discussions-to: https://ethereum-magicians.org/t/erc-8043-enable-mode-for-module-installation-in-erc-7579-smart-accounts/25901
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, which can hinder user experience. Use cases such as session key and spending limit modules would benefit from the ability to install and use modules in a single operation. This standard allows applications to opt in to install and use multiple modules under a single signature and user operation, enabling greater flexibility—particularly for scenarios where multiple modules need to work together atomically.

This standard addresses several key issues:

- **User Experience**: Reduces transaction count from N+1 to 1 for installing N modules and using them
- **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 one or more [ERC-7579] modules within a single user operation
- **Installation Signature**: An [EIP-712] signature authorizing module installations
- **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[] moduleTypeIds,
address[] modules,
bytes[] initDatas,
bytes installationSignature,
bytes userOpSignature
)
```

Where:

- `moduleTypeIds`: Array of [ERC-7579] module type identifiers
- `modules`: Array of module addresses to install
- `initDatas`: Array of initialization data to pass to each module's `onInstall` function
- `installationSignature`: [EIP-712] signature authorizing the module installations
- `userOpSignature`: Signature for validating the user operation

### EIP-712 Message Structure

The message structure MUST be:

```solidity
bytes32 constant ENABLE_MODULES_TYPEHASH = keccak256(
"EnableModules(uint256[] moduleTypeIds,address[] modules,bytes[] initDatas,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 each module using the standard ERC-7579 `installModule` flow using the corresponding `moduleTypeIds[i]`, `modules[i]`, and `initDatas[i]`
5. MUST continue with normal user operation validation using the extracted `userOpSignature`
6. MUST return `SIG_VALIDATION_FAILED` (`1`) if signature decoding fails, enabling signature is invalid, or any module installation fails

## 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_MODULES_TYPEHASH =
keccak256(
"EnableModules(uint256[] moduleTypeIds,address[] modules,bytes[] initDatas,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[] calldata moduleTypeIds,
address[] calldata modules,
bytes[] calldata initDatas,
bytes calldata installationSignature,
bytes calldata userOpSignature
) = _tryDecodeEnableMode(userOp.signature);

if (!success) {
return ERC4337Utils.SIG_VALIDATION_FAILED;
}

bytes32 structHash = _installModulesStructHash(
moduleTypeIds,
modules,
initDatas,
userOp.nonce
);

if (
isValidSignature(_hashTypedDataV4(structHash), installationSignature) ==
IERC1271.isValidSignature.selector
) {
// Install all modules
for (uint256 i = 0; i < modules.length; i++) {
_installModule(moduleTypeIds[i], modules[i], initDatas[i]);
}

// 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 installations 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)
- **Array Length Validation**: Implementations MUST ensure that `moduleTypeIds`, `modules`, and `initDatas` arrays have the same length to prevent mismatched installations

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading