Account
This directory includes contracts to build accounts for ERC-4337. These include:
-
AccountCore
: An ERC-4337 smart account implementation that includes the core logic to process user operations. -
Account
: An extension ofAccountCore
that implements the recommended features for ERC-4337 smart accounts. -
{AccountSignerERC7702}: An account implementation with low-level signature validation performed by an EOA.
-
ERC7821
: Minimal batch executor implementation contracts. Useful to enable easy batch execution for smart contracts.
Core
AccountCore
import "@openzeppelin/community-contracts/account/AccountCore.sol";
A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process user operations.
Developers must implement the AccountCore._signableUserOpHash
and AbstractSigner._rawSignatureValidation
functions to define the account’s validation logic.
This core account doesn’t include any mechanism for performing arbitrary external calls. This is an essential feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice. Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others). |
Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an
attacker to bypass the account’s security measures. Check out SignerECDSA , SignerP256 , or SignerRSA for
digital signature validation implementations.
|
-
onlyEntryPointOrSelf()
-
onlyEntryPoint()
-
entryPoint()
-
getNonce()
-
getNonce(key)
-
validateUserOp(userOp, userOpHash, missingAccountFunds)
-
_validateUserOp(userOp, userOpHash)
-
_signableUserOpHash(userOp, userOpHash)
-
_payPrefund(missingAccountFunds)
-
_checkEntryPoint()
-
_checkEntryPointOrSelf()
-
receive()
-
_rawSignatureValidation(hash, signature)
-
AccountUnauthorized(sender)
entryPoint() → contract IEntryPoint
public
Canonical entry point for the account that forwards and validates user operations.
validateUserOp(struct PackedUserOperation userOp, bytes32 userOpHash, uint256 missingAccountFunds) → uint256
public
Validates a user operation.
-
MUST validate the caller is a trusted EntryPoint
-
MUST validate that the signature is a valid signature of the userOpHash, and SHOULD return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error MUST revert.
-
MUST pay the entryPoint (caller) at least the “missingAccountFunds” (which might be zero, in case the current account’s deposit is high enough)
Returns an encoded packed validation data that is composed of the following elements:
-
authorizer
(address
): 0 for success, 1 for failure, otherwise the address of an authorizer contract -
validUntil
(uint48
): The UserOp is valid only up to this time. Zero for “infinite”. -
validAfter
(uint48
): The UserOp is valid only after this time.
_validateUserOp(struct PackedUserOperation userOp, bytes32 userOpHash) → uint256
internal
Returns the validationData for a given user operation. By default, this checks the signature of the
signable hash (produced by _signableUserOpHash
) using the abstract signer ({_rawSignatureValidation}).
The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the userOp will result in undefined behavior. |
_signableUserOpHash(struct PackedUserOperation userOp, bytes32 userOpHash) → bytes32
internal
Virtual function that returns the signable hash for a user operations. Some implementation may return
userOpHash
while other may prefer a signer-friendly value such as an EIP-712 hash describing the userOp
details.
_payPrefund(uint256 missingAccountFunds)
internal
Sends the missing funds for executing the user operation to the entryPoint
.
The missingAccountFunds
must be defined by the entrypoint when calling validateUserOp
.
_checkEntryPoint()
internal
Ensures the caller is the entryPoint
.
_checkEntryPointOrSelf()
internal
Ensures the caller is the entryPoint
or the account itself.
Account
import "@openzeppelin/community-contracts/account/Account.sol";
Extension of AccountCore
with recommended feature that most account abstraction implementation will want:
Use ERC7821 to enable external calls in batches.
|
To use this contract, the {ERC7739-_rawSignatureValidation} function must be
implemented using a specific signature verification algorithm. See SignerECDSA , SignerP256 or SignerRSA .
|
-
_signableUserOpHash(userOp, )
-
isValidSignature(hash, signature)
-
supportsInterface(interfaceId)
-
onERC1155Received(, , , , )
-
onERC1155BatchReceived(, , , , )
-
onERC721Received(, , , )
-
_domainSeparatorV4()
-
_hashTypedDataV4(structHash)
-
eip712Domain()
-
_EIP712Name()
-
_EIP712Version()
-
entryPoint()
-
getNonce()
-
getNonce(key)
-
validateUserOp(userOp, userOpHash, missingAccountFunds)
-
_validateUserOp(userOp, userOpHash)
-
_payPrefund(missingAccountFunds)
-
_checkEntryPoint()
-
_checkEntryPointOrSelf()
-
receive()
-
_rawSignatureValidation(hash, signature)
-
EIP712DomainChanged()
-
AccountUnauthorized(sender)
-
bytes32 constant _PACKED_USER_OPERATION
_signableUserOpHash(struct PackedUserOperation userOp, bytes32) → bytes32
internal
Specialization of AccountCore._signableUserOpHash
that returns a typehash following EIP-712 typed data
hashing for readability. This assumes the underlying signature scheme implements signTypedData
, which will be
the case when combined with SignerECDSA
or SignerERC7702
.
Extensions
ERC7821
import "@openzeppelin/community-contracts/account/extensions/ERC7821.sol";
Minimal batch executor following ERC-7821. Only supports basic mode (no optional "opData").
-
execute(mode, executionData)
-
supportsExecutionMode(mode)
-
_erc7821AuthorizedExecutor(caller, , )
-
UnsupportedExecutionMode()
execute(bytes32 mode, bytes executionData)
public
Executes the calls in executionData
with no optional opData
support.
Access to this function is controlled by _erc7821AuthorizedExecutor . Changing access permissions, for
example to approve calls by the ERC-4337 entrypoint, should be implement by overriding it.
|
Reverts and bubbles up error if any call fails.
supportsExecutionMode(bytes32 mode) → bool result
public
This function is provided for frontends to detect support.
Only returns true for:
- bytes32(0x01000000000000000000…)
: does not support optional opData
.
- bytes32(0x01000000000078210001…)
: supports optional opData
.
_erc7821AuthorizedExecutor(address caller, bytes32, bytes) → bool
internal
Access control mechanism for the execute
function.
By default, only the contract itself is allowed to execute.
Override this function to implement custom access control, for example to allow the ERC-4337 entrypoint to execute.
function _erc7821AuthorizedExecutor(
address caller,
bytes32 mode,
bytes calldata executionData
) internal view virtual override returns (bool) {
return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData);
}