Skip to content

Commit 83d2a24

Browse files
authored
Add Account framework (#5657)
1 parent 88962fb commit 83d2a24

38 files changed

+3082
-42
lines changed

.changeset/clean-ways-push.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`AccountERC7579`: Extension of `Account` that implements support for ERC-7579 modules of type executor, validator, and fallback handler.

.changeset/funny-years-yawn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Account`: Added a simple ERC-4337 account implementation with minimal logic to process user operations.

.changeset/lazy-poets-cheer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`SignerERC7702`: Implementation of `AbstractSigner` for Externally Owned Accounts (EOAs). Useful with ERC-7702.

.changeset/rotten-apes-lie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`IERC7821`, `ERC7821`: Interface and logic for minimal batch execution. No support for additional `opData` is included.

.changeset/strong-points-change.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`AccountERC7579Hooked`: Extension of `AccountERC7579` that implements support for ERC-7579 hook modules.

.changeset/tame-bears-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`AbstractSigner`, `SignerECDSA`, `SignerP256`, and `SignerRSA`: Add an abstract contract and various implementations for contracts that deal with signature verification.

contracts/account/Account.sol

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
import {PackedUserOperation, IAccount, IEntryPoint} from "../interfaces/draft-IERC4337.sol";
6+
import {ERC4337Utils} from "./utils/draft-ERC4337Utils.sol";
7+
import {AbstractSigner} from "../utils/cryptography/AbstractSigner.sol";
8+
9+
/**
10+
* @dev A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process
11+
* user operations.
12+
*
13+
* Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic.
14+
*
15+
* NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential
16+
* feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice.
17+
* Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others).
18+
*
19+
* IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an
20+
* attacker to bypass the account's security measures. Check out {SignerECDSA}, {SignerP256}, or {SignerRSA} for
21+
* digital signature validation implementations.
22+
*
23+
* @custom:stateless
24+
*/
25+
abstract contract Account is AbstractSigner, IAccount {
26+
/**
27+
* @dev Unauthorized call to the account.
28+
*/
29+
error AccountUnauthorized(address sender);
30+
31+
/**
32+
* @dev Revert if the caller is not the entry point or the account itself.
33+
*/
34+
modifier onlyEntryPointOrSelf() {
35+
_checkEntryPointOrSelf();
36+
_;
37+
}
38+
39+
/**
40+
* @dev Revert if the caller is not the entry point.
41+
*/
42+
modifier onlyEntryPoint() {
43+
_checkEntryPoint();
44+
_;
45+
}
46+
47+
/**
48+
* @dev Canonical entry point for the account that forwards and validates user operations.
49+
*/
50+
function entryPoint() public view virtual returns (IEntryPoint) {
51+
return ERC4337Utils.ENTRYPOINT_V08;
52+
}
53+
54+
/**
55+
* @dev Return the account nonce for the canonical sequence.
56+
*/
57+
function getNonce() public view virtual returns (uint256) {
58+
return getNonce(0);
59+
}
60+
61+
/**
62+
* @dev Return the account nonce for a given sequence (key).
63+
*/
64+
function getNonce(uint192 key) public view virtual returns (uint256) {
65+
return entryPoint().getNonce(address(this), key);
66+
}
67+
68+
/**
69+
* @inheritdoc IAccount
70+
*/
71+
function validateUserOp(
72+
PackedUserOperation calldata userOp,
73+
bytes32 userOpHash,
74+
uint256 missingAccountFunds
75+
) public virtual onlyEntryPoint returns (uint256) {
76+
uint256 validationData = _validateUserOp(userOp, userOpHash);
77+
_payPrefund(missingAccountFunds);
78+
return validationData;
79+
}
80+
81+
/**
82+
* @dev Returns the validationData for a given user operation. By default, this checks the signature of the
83+
* signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}).
84+
*
85+
* NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the
86+
* userOp will result in undefined behavior.
87+
*/
88+
function _validateUserOp(
89+
PackedUserOperation calldata userOp,
90+
bytes32 userOpHash
91+
) internal virtual returns (uint256) {
92+
return
93+
_rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), userOp.signature)
94+
? ERC4337Utils.SIG_VALIDATION_SUCCESS
95+
: ERC4337Utils.SIG_VALIDATION_FAILED;
96+
}
97+
98+
/**
99+
* @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint,
100+
* `userOpHash` is an EIP-712 hash that can be signed directly.
101+
*/
102+
function _signableUserOpHash(
103+
PackedUserOperation calldata /*userOp*/,
104+
bytes32 userOpHash
105+
) internal view virtual returns (bytes32) {
106+
return userOpHash;
107+
}
108+
109+
/**
110+
* @dev Sends the missing funds for executing the user operation to the {entrypoint}.
111+
* The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}.
112+
*/
113+
function _payPrefund(uint256 missingAccountFunds) internal virtual {
114+
if (missingAccountFunds > 0) {
115+
(bool success, ) = payable(msg.sender).call{value: missingAccountFunds}("");
116+
success; // Silence warning. The entrypoint should validate the result.
117+
}
118+
}
119+
120+
/**
121+
* @dev Ensures the caller is the {entrypoint}.
122+
*/
123+
function _checkEntryPoint() internal view virtual {
124+
address sender = msg.sender;
125+
if (sender != address(entryPoint())) {
126+
revert AccountUnauthorized(sender);
127+
}
128+
}
129+
130+
/**
131+
* @dev Ensures the caller is the {entrypoint} or the account itself.
132+
*/
133+
function _checkEntryPointOrSelf() internal view virtual {
134+
address sender = msg.sender;
135+
if (sender != address(this) && sender != address(entryPoint())) {
136+
revert AccountUnauthorized(sender);
137+
}
138+
}
139+
140+
/**
141+
* @dev Receive Ether.
142+
*/
143+
receive() external payable virtual {}
144+
}

contracts/account/README.adoc

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
11
= Account
2-
32
[.readme-notice]
43
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/account
54

6-
This directory includes contracts to build accounts for ERC-4337.
5+
This directory includes contracts to build accounts for ERC-4337. These include:
6+
7+
* {Account}: An ERC-4337 smart account implementation that includes the core logic to process user operations.
8+
* {AccountERC7579}: An extension of `Account` that implements support for ERC-7579 modules.
9+
* {AccountERC7579Hooked}: An extension of `AccountERC7579` with support for a single hook module (type 4).
10+
* {ERC7821}: Minimal batch executor implementation contracts. Useful to enable easy batch execution for smart contracts.
11+
* {ERC4337Utils}: Utility functions for working with ERC-4337 user operations.
12+
* {ERC7579Utils}: Utility functions for working with ERC-7579 modules and account modularity.
13+
14+
== Core
15+
16+
{{Account}}
17+
18+
== Extensions
19+
20+
{{AccountERC7579}}
21+
22+
{{AccountERC7579Hooked}}
23+
24+
{{ERC7821}}
725

826
== Utilities
927

0 commit comments

Comments
 (0)