Account

This directory includes contracts to build accounts for ERC-4337. These include:

Modules

Executors

ERC7579Executor

import "@openzeppelin/community-contracts/account/modules/ERC7579Executor.sol";

Basic implementation for ERC-7579 executor modules that provides execution functionality for smart accounts.

The module enables accounts to execute arbitrary operations, leveraging the execution capabilities defined in the ERC-7579 standard. Developers can customize whether an operation can be executed with custom rules by implementing the _validateExecution function in derived contracts.

This is a simplified executor that directly executes operations without delay or expiration mechanisms. For a more advanced implementation with time-delayed execution patterns and security features, see ERC7579DelayedExecutor.
Functions
  • isModuleType(moduleTypeId)

  • execute(account, salt, mode, data)

  • _validateExecution(account, salt, mode, data)

  • _execute(account, mode, salt, executionCalldata)

IERC7579Module
  • onInstall(data)

  • onUninstall(data)

Events
  • ERC7579ExecutorOperationExecuted(account, salt, mode, executionCalldata)

isModuleType(uint256 moduleTypeId) → bool public

Returns boolean value if module is a certain type

execute(address account, bytes32 salt, bytes32 mode, bytes data) → bytes[] returnData public

Executes an operation and returns the result data from the executed operation. Restricted to the account itself by default. See _execute for requirements and _validateExecution for authorization checks.

_validateExecution(address account, bytes32 salt, bytes32 mode, bytes data) → bytes internal

Validates whether the execution can proceed. This function is called before executing the operation and returns the execution calldata to be used.

Example extension:

 function _validateExecution(address account, bytes32 salt, bytes32 mode, bytes calldata data)
     internal
     override
     returns (bytes calldata)
 {
     // custom logic
     return data;
 }
Pack extra data in the data arguments (e.g. a signature) to be used in the validation process. Calldata can be sliced to extract it and return only the execution calldata.

_execute(address account, bytes32 mode, bytes32 salt, bytes executionCalldata) → bytes[] returnData internal

Internal version of execute. Emits ERC7579ExecutorOperationExecuted event.

Requirements:

  • The account must implement the {IERC7579Execution-executeFromExecutor} function.

ERC7579ExecutorOperationExecuted(address indexed account, bytes32 salt, bytes32 mode, bytes executionCalldata) event

Emitted when an operation is executed.

ERC7579DelayedExecutor

import "@openzeppelin/community-contracts/account/modules/ERC7579DelayedExecutor.sol";

Extension of ERC7579Executor that allows scheduling and executing delayed operations with expiration. This module enables time-delayed execution patterns for smart accounts.

Operation Lifecycle

  1. Scheduling: Operations are scheduled via schedule with a specified delay period. The delay period is set during onInstall and can be customized via setDelay. Each operation enters a Scheduled state and must wait for its delay period to elapse.

  2. Security Window: During the delay period, operations remain in Scheduled state but cannot be executed. Through this period, suspicious operations can be monitored and canceled via cancel if appropriate.

  3. Execution & Expiration: Once the delay period elapses, operations transition to Ready state. Operations can be executed via execute and have an expiration period after becoming executable. If an operation is not executed within the expiration period, it becomes Expired and can’t be executed. Expired operations must be rescheduled with a different salt.

Delay Management

Accounts can set their own delay periods during installation or via setDelay. The delay period is enforced even between installas and uninstalls to prevent immediate downgrades. When setting a new delay period, the new delay takes effect after a transition period defined by the current delay or minSetback, whichever is longer.

Authorization

Authorization for scheduling and canceling operations is controlled through the _validateSchedule and _validateCancel functions. These functions can be overridden to implement custom authorization logic, such as requiring specific signers or roles.

Use _scheduleAt to schedule operations at a specific points in time. This is useful to pre-schedule operations for non-deployed accounts (e.g. subscriptions).
Functions
  • state(account, salt, mode, executionCalldata)

  • state(operationId)

  • minSetback()

  • getDelay(account)

  • getExpiration(account)

  • getSchedule(account, salt, mode, executionCalldata)

  • getSchedule(operationId)

  • hashOperation(account, salt, mode, executionCalldata)

  • defaultExpiration()

  • onInstall(initData)

  • setDelay(newDelay)

  • setExpiration(newExpiration)

  • schedule(account, salt, mode, data)

  • cancel(account, salt, mode, data)

  • onUninstall()

  • _validateExecution(, , , data)

  • _validateCancel(account, , , )

  • _validateSchedule(account, , , )

  • _setDelay(account, newDelay, minimumSetback)

  • _setExpiration(account, newExpiration)

  • _scheduleAt(account, salt, mode, executionCalldata, timepoint, delay)

  • _execute(account, salt, mode, executionCalldata)

  • _cancel(account, mode, executionCalldata, salt)

  • _validateStateBitmap(operationId, allowedStates)

  • _encodeStateBitmap(operationState)

ERC7579Executor
  • isModuleType(moduleTypeId)

  • execute(account, salt, mode, data)

Events
  • ERC7579ExecutorOperationScheduled(account, operationId, salt, mode, executionCalldata, schedule)

  • ERC7579ExecutorOperationCanceled(account, operationId)

  • ERC7579ExecutorDelayUpdated(account, newDelay, effectTime)

  • ERC7579ExecutorExpirationUpdated(account, newExpiration)

ERC7579Executor
  • ERC7579ExecutorOperationExecuted(account, salt, mode, executionCalldata)

Errors
  • ERC7579ExecutorUnexpectedOperationState(operationId, currentState, allowedStates)

  • ERC7579ExecutorModuleNotInstalled()

state(address account, bytes32 salt, bytes32 mode, bytes executionCalldata) → enum ERC7579DelayedExecutor.OperationState public

Current state of an operation.

state(bytes32 operationId) → enum ERC7579DelayedExecutor.OperationState public

Same as state, but for a specific operation id.

minSetback() → uint32 public

Minimum delay after which setDelay takes effect. Set as default delay if not provided during onInstall.

getDelay(address account) → uint32 delay, uint32 pendingDelay, uint48 effectTime public

Delay for a specific account.

getExpiration(address account) → uint32 expiration public

Expiration delay for account operations.

getSchedule(address account, bytes32 salt, bytes32 mode, bytes executionCalldata) → uint48 scheduledAt, uint48 executableAt, uint48 expiresAt public

Schedule for an operation. Returns default values if not set (i.e. uint48(0), uint48(0), uint48(0)).

getSchedule(bytes32 operationId) → uint48 scheduledAt, uint48 executableAt, uint48 expiresAt public

Same as getSchedule but with the operation id.

hashOperation(address account, bytes32 salt, bytes32 mode, bytes executionCalldata) → bytes32 public

Returns the operation id.

defaultExpiration() → uint32 public

Default expiration for account operations. Set if not provided during onInstall.

onInstall(bytes initData) public

Sets up the module’s initial configuration when installed by an account. The account calling this function becomes registered with the module.

The initData may be abi.encode(uint32(initialDelay), uint32(initialExpiration)). The delay will be set to the maximum of this value and the minimum delay if provided. Otherwise, the delay will be set to minSetback and defaultExpiration respectively.

Behaves as a no-op if the module is already installed.

Requirements:

  • The account (i.e msg.sender) must implement the {IERC7579ModuleConfig} interface.

  • initData must be empty or decode correctly to (uint32, uint32).

setDelay(uint32 newDelay) public

Allows an account to update its execution delay (see getDelay).

The new delay will take effect after a transition period defined by the current delay or minSetback, whichever is longer. This prevents immediate security downgrades. Can only be called by the account itself.

setExpiration(uint32 newExpiration) public

Allows an account to update its execution expiration (see getExpiration).

schedule(address account, bytes32 salt, bytes32 mode, bytes data) public

Schedules an operation to be executed after the account’s delay period (see getDelay). Operations are uniquely identified by the combination of salt, mode, and data. See _validateSchedule for authorization checks.

cancel(address account, bytes32 salt, bytes32 mode, bytes data) public

Cancels a previously scheduled operation. Can only be called by the account that scheduled the operation. See _cancel.

onUninstall(bytes) public

Cleans up the getDelay and getExpiration values by scheduling them to 0 and respecting the previous delay and expiration values.

This function does not clean up scheduled operations. This means operations could potentially be re-executed if the module is reinstalled later. This is a deliberate design choice for efficiency, but module implementations may want to override this behavior to clear scheduled operations during uninstallation for their specific use cases.
Calling this function directly will remove the expiration (getExpiration) value and will schedule a reset of the delay (getDelay) to 0 for the account. Reinstalling the module will not immediately reset the delay if the delay reset hasn’t taken effect yet.

_validateExecution(address, bytes32, bytes32, bytes data) → bytes internal

Returns data as the execution calldata. See ERC7579Executor._execute.

This function relies on the operation state validation in _execute for authorization. Extensions of this module should override this function to implement additional validation logic if needed.

_validateCancel(address account, bytes32, bytes32, bytes) internal

Validates whether an operation can be canceled.

Example extension:

 function _validateCancel(address account, bytes32 salt, bytes32 mode, bytes calldata data) internal override {
   // e.g. require(msg.sender == account);
 }

_validateSchedule(address account, bytes32, bytes32, bytes) internal

Validates whether an operation can be scheduled.

Example extension:

 function _validateSchedule(address account, bytes32 salt, bytes32 mode, bytes calldata data) internal override {
   // e.g. require(msg.sender == account);
 }

_setDelay(address account, uint32 newDelay, uint32 minimumSetback) internal

Internal implementation for setting an account’s delay. See getDelay.

Emits an ERC7579ExecutorDelayUpdated event.

_setExpiration(address account, uint32 newExpiration) internal

Internal implementation for setting an account’s expiration. See getExpiration.

_scheduleAt(address account, bytes32 salt, bytes32 mode, bytes executionCalldata, uint48 timepoint, uint32 delay) → bytes32 operationId, struct ERC7579DelayedExecutor.Schedule schedule_ internal

Internal version of schedule that takes an account address to schedule an operation that starts its security window at at and expires after delay.

Requirements:

  • The operation must be Unknown.

_execute(address account, bytes32 salt, bytes32 mode, bytes executionCalldata) → bytes[] returnData internal

Requirements:

  • The operation must be Ready.

_cancel(address account, bytes32 mode, bytes executionCalldata, bytes32 salt) internal

Internal version of cancel that takes an account address as an argument.

Requirements:

  • The operation must be Scheduled or Ready.

Canceled operations can’t be rescheduled. Emits an ERC7579ExecutorOperationCanceled event.

_validateStateBitmap(bytes32 operationId, bytes32 allowedStates) → enum ERC7579DelayedExecutor.OperationState internal

Check that the current state of a operation matches the requirements described by the allowedStates bitmap. This bitmap should be built using _encodeStateBitmap.

If requirements are not met, reverts with a ERC7579ExecutorUnexpectedOperationState error.

_encodeStateBitmap(enum ERC7579DelayedExecutor.OperationState operationState) → bytes32 internal

Encodes a OperationState into a bytes32 representation where each bit enabled corresponds to the underlying position in the OperationState enum. For example:

0x000...10000
  ^^^^^^------ ...
        ^----- Canceled
         ^---- Executed
          ^--- Ready
           ^-- Scheduled
            ^- Unknown

ERC7579ExecutorOperationScheduled(address indexed account, bytes32 indexed operationId, bytes32 salt, bytes32 mode, bytes executionCalldata, uint48 schedule) event

Emitted when a new operation is scheduled.

ERC7579ExecutorOperationCanceled(address indexed account, bytes32 indexed operationId) event

Emitted when a new operation is canceled.

ERC7579ExecutorDelayUpdated(address indexed account, uint32 newDelay, uint48 effectTime) event

Emitted when the execution delay is updated.

ERC7579ExecutorExpirationUpdated(address indexed account, uint32 newExpiration) event

Emitted when the expiration delay is updated.

ERC7579ExecutorUnexpectedOperationState(bytes32 operationId, enum ERC7579DelayedExecutor.OperationState currentState, bytes32 allowedStates) error

The current state of a operation is not the expected. The expectedStates is a bitmap with the bits enabled for each OperationState enum position counting from right to left. See _encodeStateBitmap.

If expectedState is bytes32(0), the operation is expected to not be in any state (i.e. not exist).

ERC7579ExecutorModuleNotInstalled() error

The module is not installed on the account.

ERC7579SelectorExecutor

import "@openzeppelin/community-contracts/account/modules/ERC7579SelectorExecutor.sol";

Implementation of an ERC7579Executor that allows authorizing specific function selectors that can be executed on the account.

This module provides a way to restrict which functions can be executed on the account by maintaining a set of allowed function selectors. Only calls to functions with selectors in the set will be allowed to execute.

Functions
  • isAuthorized(account, selector)

  • selectors(account)

  • onInstall(initData)

  • onUninstall()

  • addSelectors(newSelectors)

  • removeSelectors(oldSelectors)

  • _addSelectors(account, newSelectors)

  • _removeSelectors(account, oldSelectors)

  • _validateExecution(account, , , data)

ERC7579Executor
  • isModuleType(moduleTypeId)

  • execute(account, salt, mode, data)

  • _execute(account, mode, salt, executionCalldata)

Events
  • ERC7579ExecutorSelectorAuthorized(account, selector)

  • ERC7579ExecutorSelectorRemoved(account, selector)

ERC7579Executor
  • ERC7579ExecutorOperationExecuted(account, salt, mode, executionCalldata)

Errors
  • ERC7579ExecutorSelectorNotAuthorized(selector)

isAuthorized(address account, bytes4 selector) → bool public

selectors(address account) → bytes4[] public

Returns the set of authorized selectors for the specified account.

This operation copies the entire selectors set to memory, which can be expensive or may result in unbounded computation.

onInstall(bytes initData) public

Sets up the module’s initial configuration when installed by an account. The initData should be encoded as: abi.encode(bytes4[] selectors)

onUninstall(bytes) public

Cleans up module’s configuration when uninstalled from an account. Clears all selectors.

This function has unbounded gas costs and may become uncallable if the set grows too large. See EnumerableSetExtended.clear.

addSelectors(bytes4[] newSelectors) public

Adds selectors to the set for the calling account

removeSelectors(bytes4[] oldSelectors) public

Removes a selector from the set for the calling account

_addSelectors(address account, bytes4[] newSelectors) internal

Internal version of addSelectors that takes an account as argument

_removeSelectors(address account, bytes4[] oldSelectors) internal

Internal version of removeSelectors that takes an account as argument

_validateExecution(address account, bytes32, bytes32, bytes data) → bytes internal

See ERC7579Executor._validateExecution. Validates that the selector (first 4 bytes of the actual callData) is authorized before execution.

ERC7579ExecutorSelectorAuthorized(address indexed account, bytes4 selector) event

Emitted when a selector is added to the set

ERC7579ExecutorSelectorRemoved(address indexed account, bytes4 selector) event

Emitted when a selector is removed from the set

ERC7579ExecutorSelectorNotAuthorized(bytes4 selector) error

Error thrown when attempting to execute a non-authorized selector

Validators

ERC7579Validator

import "@openzeppelin/community-contracts/account/modules/ERC7579Validator.sol";

Abstract validator module for ERC-7579 accounts.

This contract provides the base implementation for signature validation in ERC-7579 accounts. Developers must implement the onInstall, onUninstall, and _rawERC7579Validation functions in derived contracts to define the specific signature validation logic.

Example usage:

contract MyValidatorModule is ERC7579Validator {
    function onInstall(bytes calldata data) public {
        // Install logic here
    }

    function onUninstall(bytes calldata data) public {
        // Uninstall logic here
    }

    function _rawERC7579Validation(
        address account,
        bytes32 hash,
        bytes calldata signature
    ) internal view override returns (bool) {
        // Signature validation logic here
    }
}

Developers can restrict other operations by using the internal _rawERC7579Validation. Example usage:

function execute(
    address account,
    Mode mode,
    bytes calldata executionCalldata,
    bytes32 salt,
    bytes calldata signature
) public virtual {
    require(_rawERC7579Validation(account, hash, signature));
    // ... rest of execute logic
}
Functions
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

  • _rawERC7579Validation(account, hash, signature)

IERC7579Module
  • onInstall(data)

  • onUninstall(data)

isModuleType(uint256 moduleTypeId) → bool public

Returns boolean value if module is a certain type

validateUserOp(struct PackedUserOperation userOp, bytes32 userOpHash) → uint256 public

Validates a UserOperation

isValidSignatureWithSender(address, bytes32 hash, bytes signature) → bytes4 public

See {IERC7579Validator-isValidSignatureWithSender}.

Ignores the sender parameter and validates using _rawERC7579Validation. Consider overriding this function to implement custom validation logic based on the original sender.

_rawERC7579Validation(address account, bytes32 hash, bytes signature) → bool internal

Validation algorithm.

Validation is a critical security function. Implementations must carefully handle cryptographic verification to prevent unauthorized access.

ERC7579Signature

import "@openzeppelin/community-contracts/account/modules/ERC7579Signature.sol";

Implementation of ERC7579Validator module using ERC-7913 signature verification.

This validator allows ERC-7579 accounts to integrate with address-less cryptographic keys and account signatures through the ERC-7913 signature verification system. Each account can store its own ERC-7913 formatted signer (a concatenation of a verifier address and a key: verifier || key).

This enables accounts to use signature schemes without requiring each key to have its own Ethereum address.A smart account with this module installed can keep an emergency key as a backup.

Functions
  • signer(account)

  • onInstall(data)

  • onUninstall()

  • setSigner(signer_)

  • _setSigner(account, signer_)

  • _rawERC7579Validation(account, hash, signature)

ERC7579Validator
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

Events
  • ERC7579SignatureSignerSet(account, signer)

Errors
  • ERC7579SignatureInvalidSignerLength()

signer(address account) → bytes public

Return the ERC-7913 signer (i.e. verifier || key).

onInstall(bytes data) public

See {IERC7579Module-onInstall}.

An account can only call onInstall once. If called directly by the account, the signer will be set to the provided data. Future installations will behave as a no-op.

onUninstall(bytes) public

See {IERC7579Module-onUninstall}.

The signer’s key will be removed if the account calls this function, potentially making the account unusable. As an account operator, make sure to uninstall to a predefined path in your account that properly handles side effects of uninstallation. See {AccountERC7579-uninstallModule}.

setSigner(bytes signer_) public

Sets the ERC-7913 signer (i.e. verifier || key) for the calling account.

_setSigner(address account, bytes signer_) internal

Internal version of setSigner that takes an account as argument without validating signer_.

_rawERC7579Validation(address account, bytes32 hash, bytes signature) → bool internal

Validates a signature using ERC-7913 verification.

This base implementation ignores the sender parameter and validates using the account’s stored signer. Derived contracts can override this to implement custom validation logic based on the sender.

ERC7579SignatureSignerSet(address indexed account, bytes signer) event

Emitted when the signer is set.

ERC7579SignatureInvalidSignerLength() error

Thrown when the signer length is less than 20 bytes.

ERC7579Multisig

import "@openzeppelin/community-contracts/account/modules/ERC7579Multisig.sol";

Implementation of an ERC7579Validator that uses ERC-7913 signers for multisignature validation.

This module provides a base implementation for multisignature validation that can be attached to any function through the _rawERC7579Validation internal function. The signers are represented using the ERC-7913 format, which concatenates a verifier address and a key: verifier || key.

A smart account with this module installed can require multiple signers to approve operations before they are executed, such as requiring 3-of-5 guardians to approve a social recovery operation.

Functions
  • onInstall(initData)

  • onUninstall()

  • signers(account)

  • isSigner(account, signer)

  • _signers(account)

  • threshold(account)

  • addSigners(newSigners)

  • removeSigners(oldSigners)

  • setThreshold(newThreshold)

  • _rawERC7579Validation(account, hash, signature)

  • _addSigners(account, newSigners)

  • _removeSigners(account, oldSigners)

  • _setThreshold(account, newThreshold)

  • _validateReachableThreshold(account)

  • _validateSignatures(account, hash, signingSigners, signatures)

  • _validateThreshold(account, validatingSigners)

ERC7579Validator
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

Events
  • ERC7913SignerAdded(account, signer)

  • ERC7913SignerRemoved(account, signer)

  • ERC7913ThresholdSet(account, threshold)

Errors
  • ERC7579MultisigAlreadyExists(signer)

  • ERC7579MultisigNonexistentSigner(signer)

  • ERC7579MultisigInvalidSigner(signer)

  • ERC7579MultisigUnreachableThreshold(signers, threshold)

onInstall(bytes initData) public

Sets up the module’s initial configuration when installed by an account. See ERC7579DelayedExecutor.onInstall. Besides the delay setup, the initdata can include signers and threshold.

The initData should be encoded as: abi.encode(bytes[] signers, uint256 threshold)

If no signers or threshold are provided, the multisignature functionality will be disabled until they are added later.

An account can only call onInstall once. If called directly by the account, the signer will be set to the provided data. Future installations will behave as a no-op.

onUninstall(bytes) public

Cleans up module’s configuration when uninstalled from an account. Clears all signers and resets the threshold.

This function has unbounded gas costs and may become uncallable if the set grows too large. See {EnumerableSet-clear}.

signers(address account) → bytes[] public

Returns the set of authorized signers for the specified account.

This operation copies the entire signers set to memory, which can be expensive or may result in unbounded computation.

isSigner(address account, bytes signer) → bool public

Returns whether the signer is an authorized signer for the specified account.

_signers(address account) → struct EnumerableSet.BytesSet internal

Returns the set of authorized signers for the specified account.

threshold(address account) → uint256 public

Returns the minimum number of signers required to approve a multisignature operation for the specified account.

addSigners(bytes[] newSigners) public

Adds new signers to the authorized set for the calling account. Can only be called by the account itself.

Requirements:

  • Each of newSigners must be at least 20 bytes long.

  • Each of newSigners must not be already authorized.

removeSigners(bytes[] oldSigners) public

Removes signers from the authorized set for the calling account. Can only be called by the account itself.

Requirements:

  • Each of oldSigners must be authorized.

  • After removal, the threshold must still be reachable.

setThreshold(uint256 newThreshold) public

Sets the threshold for the calling account. Can only be called by the account itself.

Requirements:

  • The threshold must be reachable with the current number of signers.

_rawERC7579Validation(address account, bytes32 hash, bytes signature) → bool internal

Returns whether the number of valid signatures meets or exceeds the threshold set for the target account.

The signature should be encoded as: abi.encode(bytes[] signingSigners, bytes[] signatures)

Where signingSigners are the authorized signers and signatures are their corresponding signatures of the operation hash.

_addSigners(address account, bytes[] newSigners) internal

Adds the newSigners to those allowed to sign on behalf of the account.

Requirements:

_removeSigners(address account, bytes[] oldSigners) internal

Removes the oldSigners from the authorized signers for the account.

Requirements:

_setThreshold(address account, uint256 newThreshold) internal

Sets the signatures threshold required to approve a multisignature operation.

Requirements:

_validateReachableThreshold(address account) internal

Validates the current threshold is reachable with the number of signers.

Requirements:

_validateSignatures(address account, bytes32 hash, bytes[] signingSigners, bytes[] signatures) → bool valid internal

Validates the signatures using the signers and their corresponding signatures. Returns whether the signers are authorized and the signatures are valid for the given hash.

The signers must be ordered by their keccak256 hash to prevent duplications and to optimize the verification process. The function will return false if any signer is not authorized or if the signatures are invalid for the given hash.

Requirements:

  • The signatures array must be at least the signers array’s length.

_validateThreshold(address account, bytes[] validatingSigners) → bool internal

Validates that the number of signers meets the threshold requirement. Assumes the signers were already validated. See _validateSignatures for more details.

ERC7913SignerAdded(address indexed account, bytes signer) event

Emitted when signers are added.

ERC7913SignerRemoved(address indexed account, bytes signer) event

Emitted when signers are removed.

ERC7913ThresholdSet(address indexed account, uint256 threshold) event

Emitted when the threshold is updated.

ERC7579MultisigAlreadyExists(bytes signer) error

The signer already exists.

ERC7579MultisigNonexistentSigner(bytes signer) error

The signer does not exist.

ERC7579MultisigInvalidSigner(bytes signer) error

The signer is less than 20 bytes long.

ERC7579MultisigUnreachableThreshold(uint256 signers, uint256 threshold) error

The threshold is unreachable given the number of signers.

ERC7579MultisigWeighted

import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigWeighted.sol";

Extension of ERC7579Multisig that supports weighted signatures.

This module extends the multisignature module to allow assigning different weights to each signer, enabling more flexible governance schemes. For example, some guardians could have higher weight than others, allowing for weighted voting or prioritized authorization.

Example use case:

A smart account with this module installed can schedule social recovery operations after obtaining approval from guardians with sufficient total weight (e.g., requiring a total weight of 10, with 3 guardians weighted as 5, 3, and 2), and then execute them after the time delay has passed.

When setting a threshold value, ensure it matches the scale used for signer weights. For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require signatures with a total weight of at least 4 (e.g., one with weight 1 and one with weight 3).
Functions
  • onInstall(initData)

  • onUninstall(data)

  • signerWeight(account, signer)

  • totalWeight(account)

  • setSignerWeights(signers, weights)

  • _signerWeight(account, signer)

  • _setSignerWeights(account, signers, newWeights)

  • _addSigners(account, newSigners)

  • _removeSigners(account, oldSigners)

  • _validateReachableThreshold(account)

  • _validateThreshold(account, validatingSigners)

  • _weightSigners(account, signers)

ERC7579Multisig
  • signers(account)

  • isSigner(account, signer)

  • _signers(account)

  • threshold(account)

  • addSigners(newSigners)

  • removeSigners(oldSigners)

  • setThreshold(newThreshold)

  • _rawERC7579Validation(account, hash, signature)

  • _setThreshold(account, newThreshold)

  • _validateSignatures(account, hash, signingSigners, signatures)

ERC7579Validator
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

Events
  • ERC7579MultisigWeightChanged(account, signer, weight)

ERC7579Multisig
  • ERC7913SignerAdded(account, signer)

  • ERC7913SignerRemoved(account, signer)

  • ERC7913ThresholdSet(account, threshold)

Errors
  • ERC7579MultisigInvalidWeight(signer, weight)

  • ERC7579MultisigMismatchedLength()

ERC7579Multisig
  • ERC7579MultisigAlreadyExists(signer)

  • ERC7579MultisigNonexistentSigner(signer)

  • ERC7579MultisigInvalidSigner(signer)

  • ERC7579MultisigUnreachableThreshold(signers, threshold)

onInstall(bytes initData) public

Sets up the module’s initial configuration when installed by an account. Besides the standard delay and signer configuration, this can also include signer weights.

The initData should be encoded as: abi.encode(bytes[] signers, uint256 threshold, uint256[] weights)

If weights are not provided but signers are, all signers default to weight 1.

An account can only call onInstall once. If called directly by the account, the signer will be set to the provided data. Future installations will behave as a no-op.

onUninstall(bytes data) public

Cleans up module’s configuration when uninstalled from an account. Clears all signers, weights, and total weights.

signerWeight(address account, bytes signer) → uint256 public

Gets the weight of a signer for a specific account. Returns 0 if the signer is not authorized.

totalWeight(address account) → uint256 public

Gets the total weight of all signers for a specific account.

setSignerWeights(bytes[] signers, uint256[] weights) public

Sets weights for signers for the calling account. Can only be called by the account itself.

_signerWeight(address account, bytes signer) → uint256 internal

Gets the weight of the current signer. Returns 1 if not explicitly set. This internal function doesn’t check if the signer is authorized.

_setSignerWeights(address account, bytes[] signers, uint256[] newWeights) internal

Sets weights for multiple signers at once. Internal version without access control.

Requirements:

Emits ERC7579MultisigWeightChanged for each signer.

_addSigners(address account, bytes[] newSigners) internal

Override to add weight tracking. See ERC7579Multisig._addSigners. Each new signer has a default weight of 1.

_removeSigners(address account, bytes[] oldSigners) internal

Override to handle weight tracking during removal. See ERC7579Multisig._removeSigners.

_validateReachableThreshold(address account) internal

Override to validate threshold against total weight instead of signer count.

This function intentionally does not call super._validateReachableThreshold because the base implementation assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple implementations of this function may exist in the contract, so important side effects may be missed depending on the linearization order.

_validateThreshold(address account, bytes[] validatingSigners) → bool internal

Validates that the total weight of signers meets the threshold requirement. Overrides the base implementation to use weights instead of count.

This function intentionally does not call super._validateThreshold because the base implementation assumes each signer has a weight of 1, which is incompatible with this weighted implementation.

_weightSigners(address account, bytes[] signers) → uint256 internal

Calculates the total weight of a set of signers.

ERC7579MultisigWeightChanged(address indexed account, bytes indexed signer, uint256 weight) event

Emitted when a signer’s weight is changed.

ERC7579MultisigInvalidWeight(bytes signer, uint256 weight) error

Thrown when a signer’s weight is invalid.

ERC7579MultisigMismatchedLength() error

Thrown when the arrays lengths don’t match.

ERC7579MultisigConfirmation

import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigConfirmation.sol";

Extension of ERC7579Multisig that requires explicit confirmation signatures from new signers when they are being added to the multisig.

This module ensures that only willing participants can be added as signers to a multisig by requiring each new signer to provide a valid signature confirming their consent to be added. Each signer must sign an EIP-712 message to confirm their addition.

Use this module to ensure that all guardians in a social recovery or multisig setup have explicitly agreed to their roles.
Functions
  • _signableConfirmationHash(account, deadline)

  • _addSigners(account, newSigners)

EIP712
  • _domainSeparatorV4()

  • _hashTypedDataV4(structHash)

  • eip712Domain()

  • _EIP712Name()

  • _EIP712Version()

ERC7579Multisig
  • onInstall(initData)

  • onUninstall()

  • signers(account)

  • isSigner(account, signer)

  • _signers(account)

  • threshold(account)

  • addSigners(newSigners)

  • removeSigners(oldSigners)

  • setThreshold(newThreshold)

  • _rawERC7579Validation(account, hash, signature)

  • _removeSigners(account, oldSigners)

  • _setThreshold(account, newThreshold)

  • _validateReachableThreshold(account)

  • _validateSignatures(account, hash, signingSigners, signatures)

  • _validateThreshold(account, validatingSigners)

ERC7579Validator
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

Events
IERC5267
  • EIP712DomainChanged()

ERC7579Multisig
  • ERC7913SignerAdded(account, signer)

  • ERC7913SignerRemoved(account, signer)

  • ERC7913ThresholdSet(account, threshold)

Errors
  • ERC7579MultisigInvalidConfirmationSignature(signer)

  • ERC7579MultisigExpiredConfirmation(deadline)

ERC7579Multisig
  • ERC7579MultisigAlreadyExists(signer)

  • ERC7579MultisigNonexistentSigner(signer)

  • ERC7579MultisigInvalidSigner(signer)

  • ERC7579MultisigUnreachableThreshold(signers, threshold)

_signableConfirmationHash(address account, uint256 deadline) → bytes32 internal

Generates a hash that signers must sign to confirm their addition to the multisig of account.

_addSigners(address account, bytes[] newSigners) internal

Extends ERC7579Multisig._addSigners _addSigners to require confirmation signatures Each entry in newSigners must be ABI-encoded as:

abi.encode(deadline,signer,signature); // uint256, bytes, bytes
  • signer: The ERC-7913 signer to add

  • signature: The signature from this signer confirming their addition

The function verifies each signature before adding the signer. If any signature is invalid, the function reverts with ERC7579MultisigInvalidConfirmationSignature.

ERC7579MultisigInvalidConfirmationSignature(bytes signer) error

Error thrown when a `signer’s confirmation signature is invalid

ERC7579MultisigExpiredConfirmation(uint256 deadline) error

Error thrown when a confirmation signature has expired

ERC7579MultisigStorage

import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigStorage.sol";

Extension of ERC7579Multisig that allows storing presigned approvals in storage.

This module extends the multisignature module to allow signers to presign operations, which are then stored in a mapping and can be used during validation. This enables more flexible multisignature workflows where signatures can be collected over time without requiring all signers to be online simultaneously.

When validating signatures, if a signature is empty, it indicates a presignature and the validation will check the storage mapping instead of cryptographic verification.

Functions
  • presigned(account, signer, hash)

  • presign(account, signer, hash, signature)

  • _validateSignatures(account, hash, signingSigners, signatures)

ERC7579Multisig
  • onInstall(initData)

  • onUninstall()

  • signers(account)

  • isSigner(account, signer)

  • _signers(account)

  • threshold(account)

  • addSigners(newSigners)

  • removeSigners(oldSigners)

  • setThreshold(newThreshold)

  • _rawERC7579Validation(account, hash, signature)

  • _addSigners(account, newSigners)

  • _removeSigners(account, oldSigners)

  • _setThreshold(account, newThreshold)

  • _validateReachableThreshold(account)

  • _validateThreshold(account, validatingSigners)

ERC7579Validator
  • isModuleType(moduleTypeId)

  • validateUserOp(userOp, userOpHash)

  • isValidSignatureWithSender(, hash, signature)

Events
  • ERC7579MultisigStoragePresigned(account, hash, signer)

ERC7579Multisig
  • ERC7913SignerAdded(account, signer)

  • ERC7913SignerRemoved(account, signer)

  • ERC7913ThresholdSet(account, threshold)

Errors
ERC7579Multisig
  • ERC7579MultisigAlreadyExists(signer)

  • ERC7579MultisigNonexistentSigner(signer)

  • ERC7579MultisigInvalidSigner(signer)

  • ERC7579MultisigUnreachableThreshold(signers, threshold)

presigned(address account, bytes signer, bytes32 hash) → bool public

Returns whether a signer has presigned a specific hash for the account

presign(address account, bytes signer, bytes32 hash, bytes signature) public

Allows a signer to presign a hash by providing a valid signature. The signature will be verified and if valid, the presignature will be stored.

Emits ERC7579MultisigStoragePresigned if the signature is valid and the hash is not already signed, otherwise acts as a no-op.

Does not check if the signer is authorized for the account. Valid signatures from invalid signers won’t be executable. See _validateSignatures for more details.

_validateSignatures(address account, bytes32 hash, bytes[] signingSigners, bytes[] signatures) → bool valid internal

If a signature is empty, it indicates a presignature and the validation will check the storage mapping instead of cryptographic verification. See {sign} for more details.

ERC7579MultisigStoragePresigned(address indexed account, bytes32 indexed hash, bytes signer) event

Emitted when a signer signs a hash

Paymaster

PaymasterCore

import "@openzeppelin/community-contracts/account/paymaster/PaymasterCore.sol";

A simple ERC4337 paymaster implementation. This base implementation only includes the minimal logic to validate and pay for user operations.

Developers must implement the PaymasterCore._validatePaymasterUserOp function to define the paymaster’s validation and payment logic. The context parameter is used to pass data between the validation and execution phases.

The paymaster includes support to call the {IEntryPointStake} interface to manage the paymaster’s deposits and stakes through the internal functions deposit, withdraw, addStake, unlockStake and withdrawStake.

  • Deposits are used to pay for user operations.

  • Stakes are used to guarantee the paymaster’s reputation and obtain more flexibility in accessing storage.

See [Paymaster’s unstaked reputation rules](https://eips.ethereum.org/EIPS/eip-7562#unstaked-paymasters-reputation-rules)  for more details on the paymaster’s storage access limitations.
Modifiers
  • onlyEntryPoint()

  • onlyWithdrawer()

Functions
  • entryPoint()

  • validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • postOp(mode, context, actualGasCost, actualUserOpFeePerGas)

  • _validatePaymasterUserOp(userOp, userOpHash, requiredPreFund)

  • _postOp(, , , )

  • deposit()

  • withdraw(to, value)

  • addStake(unstakeDelaySec)

  • unlockStake()

  • withdrawStake(to)

  • _checkEntryPoint()

  • _authorizeWithdraw()

Errors
  • PaymasterUnauthorized(sender)

onlyEntryPoint() modifier

Revert if the caller is not the entry point.

onlyWithdrawer() modifier

entryPoint() → contract IEntryPoint public

Canonical entry point for the account that forwards and validates user operations.

validatePaymasterUserOp(struct PackedUserOperation userOp, bytes32 userOpHash, uint256 maxCost) → bytes context, uint256 validationData public

Validates whether the paymaster is willing to pay for the user operation. See {IAccount-validateUserOp} for additional information on the return value.

Bundlers will reject this method if it modifies the state, unless it’s whitelisted.

postOp(enum IPaymaster.PostOpMode mode, bytes context, uint256 actualGasCost, uint256 actualUserOpFeePerGas) public

Verifies the sender is the entrypoint.

_validatePaymasterUserOp(struct PackedUserOperation userOp, bytes32 userOpHash, uint256 requiredPreFund) → bytes context, uint256 validationData internal

Internal validation of whether the paymaster is willing to pay for the user operation. Returns the context to be passed to postOp and the validation data.

The requiredPreFund is the amount the paymaster has to pay (in native tokens). It’s calculated as requiredGas * userOp.maxFeePerGas, where required gas can be calculated from the user operation as verificationGasLimit + callGasLimit + paymasterVerificationGasLimit + paymasterPostOpGasLimit + preVerificationGas

_postOp(enum IPaymaster.PostOpMode, bytes, uint256, uint256) internal

Handles post user operation execution logic. The caller must be the entry point.

It receives the context returned by _validatePaymasterUserOp. Function is not called if no context is returned by validatePaymasterUserOp.

The actualUserOpFeePerGas is not tx.gasprice. A user operation can be bundled with other transactions making the gas price of the user operation to differ.

deposit() public

Calls {IEntryPointStake-depositTo}.

withdraw(address payable to, uint256 value) public

Calls {IEntryPointStake-withdrawTo}.

addStake(uint32 unstakeDelaySec) public

Calls {IEntryPointStake-addStake}.

unlockStake() public

Calls {IEntryPointStake-unlockStake}.

withdrawStake(address payable to) public

Calls {IEntryPointStake-withdrawStake}.

_checkEntryPoint() internal

Ensures the caller is the entryPoint.

_authorizeWithdraw() internal

Checks whether msg.sender withdraw funds stake or deposit from the entrypoint on paymaster’s behalf.

Use of an access control modifier such as {Ownable-onlyOwner} is recommended.

function _authorizeUpgrade() internal onlyOwner {}

PaymasterUnauthorized(address sender) error

Unauthorized call to the paymaster.

PaymasterERC20

import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC20.sol";

Extension of PaymasterCore that enables users to pay gas with ERC-20 tokens.

To enable this feature, developers must implement the _fetchDetails function:

function _fetchDetails(
    PackedUserOperation calldata userOp,
    bytes32 userOpHash
) internal view override returns (uint256 validationData, IERC20 token, uint256 tokenPrice) {
    // Implement logic to fetch the token, and token price from the userOp
}

The contract follows a pre-charge and refund model: 1. During validation, it pre-charges the maximum possible gas cost 2. After execution, it refunds any unused gas back to the user

Functions
  • _validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • _prefund(userOp, , token, tokenPrice, prefunder_, maxCost)

  • _postOp(, context, actualGasCost, actualUserOpFeePerGas)

  • _refund(token, tokenPrice, actualGasCost, actualUserOpFeePerGas, prefunder, prefundAmount, )

  • _fetchDetails(userOp, userOpHash)

  • _postOpCost()

  • _tokenPriceDenominator()

  • _erc20Cost(cost, feePerGas, tokenPrice)

  • withdrawTokens(token, recipient, amount)

PaymasterCore
  • entryPoint()

  • validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • postOp(mode, context, actualGasCost, actualUserOpFeePerGas)

  • deposit()

  • withdraw(to, value)

  • addStake(unstakeDelaySec)

  • unlockStake()

  • withdrawStake(to)

  • _checkEntryPoint()

  • _authorizeWithdraw()

Events
  • UserOperationSponsored(userOpHash, token, tokenAmount, tokenPrice)

Errors
  • PaymasterERC20FailedRefund(token, prefundAmount, actualAmount, prefundContext)

PaymasterCore
  • PaymasterUnauthorized(sender)

_validatePaymasterUserOp(struct PackedUserOperation userOp, bytes32 userOpHash, uint256 maxCost) → bytes context, uint256 validationData internal

Attempts to retrieve the token and tokenPrice from the user operation (see _fetchDetails) and prefund the user operation using these values and the maxCost argument (see _prefund).

Returns abi.encodePacked(userOpHash, token, tokenPrice, prefundAmount, prefunder, prefundContext) in context if the prefund is successful. Otherwise, it returns empty bytes.

_prefund(struct PackedUserOperation userOp, bytes32, contract IERC20 token, uint256 tokenPrice, address prefunder_, uint256 maxCost) → bool prefunded, uint256 prefundAmount, address prefunder, bytes prefundContext internal

Prefunds the userOp by charging the maximum possible gas cost (maxCost) in ERC-20 token.

The token and tokenPrice is obtained from the {fetchDetails} function and are funded by the prefunder, which is the user operation sender by default. The prefundAmount is calculated using _erc20Cost.

Returns a prefundContext that’s passed to the _postOp function through its context return value.

Consider not reverting if the prefund fails when overriding this function. This is to avoid reverting during the validation phase of the user operation, which may penalize the paymaster’s reputation according to ERC-7562 validation rules.

_postOp(enum IPaymaster.PostOpMode, bytes context, uint256 actualGasCost, uint256 actualUserOpFeePerGas) internal

Attempts to refund the user operation after execution. See _refund.

Reverts with PaymasterERC20FailedRefund if the refund fails.

This function may revert after the user operation has been executed without reverting the user operation itself. Consider implementing a mechanism to handle this case gracefully.

_refund(contract IERC20 token, uint256 tokenPrice, uint256 actualGasCost, uint256 actualUserOpFeePerGas, address prefunder, uint256 prefundAmount, bytes) → bool refunded, uint256 actualAmount internal

Refunds any unused gas back to the user (i.e. prefundAmount - actualAmount) in token.

The actualAmount is calculated using _erc20Cost and the actualGasCost, actualUserOpFeePerGas, prefundContext and the tokenPrice from the _postOp's context.

_fetchDetails(struct PackedUserOperation userOp, bytes32 userOpHash) → uint256 validationData, contract IERC20 token, uint256 tokenPrice internal

Retrieves payment details for a user operation.

The values returned by this internal function are:

  • validationData: ERC-4337 validation data, indicating success/failure and optional time validity (validAfter, validUntil).

  • token: Address of the ERC-20 token used for payment to the paymaster.

  • tokenPrice: Price of the token in native currency, scaled by _tokenPriceDenominator().

Calculating the token price

Given gas fees are paid in native currency, developers can use the ERC20 price unit / native price unit ratio to calculate the price of an ERC20 token price in native currency. However, the token may have a different number of decimals than the native currency. For a a generalized formula considering prices in USD and decimals, consider using:

(<ERC-20 token price in $> / 10**<ERC-20 decimals>) / (<Native token price in $> / 1e18) * _tokenPriceDenominator()

For example, suppose token is USDC ($1 with 6 decimals) and native currency is ETH (assuming $2524.86 with 18 decimals), then each unit (1e-6) of USDC is worth (1 / 1e6) / ((252486 / 1e2) / 1e18) = 396061563.8094785 wei. The _tokenPriceDenominator() ensures precision by avoiding fractional value loss. (i.e. the 0.8094785 part).

_postOpCost() → uint256 internal

Over-estimates the cost of the post-operation logic.

_tokenPriceDenominator() → uint256 internal

Denominator used for interpreting the tokenPrice returned by _fetchDetails as "fixed point" in _erc20Cost.

_erc20Cost(uint256 cost, uint256 feePerGas, uint256 tokenPrice) → uint256 internal

Calculates the cost of the user operation in ERC-20 tokens.

withdrawTokens(contract IERC20 token, address recipient, uint256 amount) public

Public function that allows the withdrawer to extract ERC-20 tokens resulting from gas payments.

UserOperationSponsored(bytes32 indexed userOpHash, address indexed token, uint256 tokenAmount, uint256 tokenPrice) event

Emitted when a user operation identified by userOpHash is sponsored by this paymaster using the specified ERC-20 token. The tokenAmount is the amount charged for the operation, and tokenPrice is the price of the token in native currency (e.g., ETH).

PaymasterERC20FailedRefund(contract IERC20 token, uint256 prefundAmount, uint256 actualAmount, bytes prefundContext) error

Throws when the paymaster fails to refund the difference between the prefundAmount and the actualAmount of token.

PaymasterERC20Guarantor

import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC20Guarantor.sol";

Extension of PaymasterERC20 that enables third parties to guarantee user operations.

This contract allows a guarantor to pre-fund user operations on behalf of users. The guarantor pays the maximum possible gas cost upfront, and after execution: 1. If the user repays the guarantor, the guarantor gets their funds back 2. If the user fails to repay, the guarantor absorbs the cost

A common use case is for guarantors to pay for the operations of users claiming airdrops. In this scenario:

  • The guarantor pays the gas fees upfront

  • The user claims their airdrop tokens

  • The user repays the guarantor from the claimed tokens

  • If the user fails to repay, the guarantor absorbs the cost

The guarantor is identified through the _fetchGuarantor function, which must be implemented by developers to determine who can guarantee operations. This allows for flexible guarantor selection logic based on the specific requirements of the application.

Functions
  • _prefund(userOp, userOpHash, token, tokenPrice, prefunder_, maxCost)

  • _refund(token, tokenPrice, actualGasCost, actualUserOpFeePerGas, prefunder, prefundAmount, prefundContext)

  • _fetchGuarantor(userOp)

  • _guaranteedPostOpCost()

PaymasterERC20
  • _validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • _postOp(, context, actualGasCost, actualUserOpFeePerGas)

  • _fetchDetails(userOp, userOpHash)

  • _postOpCost()

  • _tokenPriceDenominator()

  • _erc20Cost(cost, feePerGas, tokenPrice)

  • withdrawTokens(token, recipient, amount)

PaymasterCore
  • entryPoint()

  • validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • postOp(mode, context, actualGasCost, actualUserOpFeePerGas)

  • deposit()

  • withdraw(to, value)

  • addStake(unstakeDelaySec)

  • unlockStake()

  • withdrawStake(to)

  • _checkEntryPoint()

  • _authorizeWithdraw()

Events
  • UserOperationGuaranteed(userOpHash, guarantor, prefundAmount)

PaymasterERC20
  • UserOperationSponsored(userOpHash, token, tokenAmount, tokenPrice)

Errors
PaymasterERC20
  • PaymasterERC20FailedRefund(token, prefundAmount, actualAmount, prefundContext)

PaymasterCore
  • PaymasterUnauthorized(sender)

_prefund(struct PackedUserOperation userOp, bytes32 userOpHash, contract IERC20 token, uint256 tokenPrice, address prefunder_, uint256 maxCost) → bool prefunded, uint256 prefundAmount, address prefunder, bytes prefundContext internal

Prefunds the user operation using either the guarantor or the default prefunder. See PaymasterERC20._prefund.

Returns abi.encodePacked(…​, userOp.sender) in prefundContext to allow the refund process to identify the user operation sender.

_refund(contract IERC20 token, uint256 tokenPrice, uint256 actualGasCost, uint256 actualUserOpFeePerGas, address prefunder, uint256 prefundAmount, bytes prefundContext) → bool refunded, uint256 actualAmount internal

Handles the refund process for guaranteed operations.

If the operation was guaranteed, it attempts to get repayment from the user first and then refunds the guarantor. Otherwise, fallback to PaymasterERC20._refund.

For guaranteed user operations where the user paid the actualGasCost back, this function doesn’t call super._refund. Consider whether there are side effects in the parent contract that need to be executed.

_fetchGuarantor(struct PackedUserOperation userOp) → address guarantor internal

Fetches the guarantor address and validation data from the user operation.

Return address(0) to disable the guarantor feature. If supported, ensure explicit consent (e.g., signature verification) to prevent unauthorized use.

_guaranteedPostOpCost() → uint256 internal

Over-estimates the cost of the post-operation logic. Added on top of guaranteed userOps post-operation cost.

UserOperationGuaranteed(bytes32 indexed userOpHash, address indexed guarantor, uint256 prefundAmount) event

Emitted when a user operation identified by userOpHash is guaranteed by a guarantor for prefundAmount.

PaymasterERC721Owner

import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC721Owner.sol";

Extension of PaymasterCore that supports account based on ownership of an ERC-721 token.

This paymaster will sponsor user operations if the user has at least 1 token of the token specified during construction (or via _setToken).

Functions
  • constructor(token_)

  • token()

  • _setToken(token_)

  • _validatePaymasterUserOp(userOp, , )

PaymasterCore
  • entryPoint()

  • validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • postOp(mode, context, actualGasCost, actualUserOpFeePerGas)

  • _postOp(, , , )

  • deposit()

  • withdraw(to, value)

  • addStake(unstakeDelaySec)

  • unlockStake()

  • withdrawStake(to)

  • _checkEntryPoint()

  • _authorizeWithdraw()

Events
  • PaymasterERC721OwnerTokenSet(token)

Errors
PaymasterCore
  • PaymasterUnauthorized(sender)

constructor(contract IERC721 token_) internal

token() → contract IERC721 public

ERC-721 token used to validate the user operation.

_setToken(contract IERC721 token_) internal

Sets the ERC-721 token used to validate the user operation.

_validatePaymasterUserOp(struct PackedUserOperation userOp, bytes32, uint256) → bytes context, uint256 validationData internal

Internal validation of whether the paymaster is willing to pay for the user operation. Returns the context to be passed to postOp and the validation data.

The default context is bytes(0). Developers that add a context when overriding this function MUST also override _postOp to process the context passed along.

PaymasterERC721OwnerTokenSet(contract IERC721 token) event

Emitted when the paymaster token is set.

PaymasterSigner

import "@openzeppelin/community-contracts/account/paymaster/PaymasterSigner.sol";

Extension of PaymasterCore that adds signature validation. See {SignerECDSA}, {SignerP256} or {SignerRSA}.

Example of usage:

contract MyPaymasterECDSASigner is PaymasterSigner, SignerECDSA {
    constructor(address signerAddr) EIP712("MyPaymasterECDSASigner", "1") SignerECDSA(signerAddr) {}
}
Functions
  • _signableUserOpHash(userOp, validAfter, validUntil)

  • _validatePaymasterUserOp(userOp, , )

  • _decodePaymasterUserOp(userOp)

PaymasterCore
  • entryPoint()

  • validatePaymasterUserOp(userOp, userOpHash, maxCost)

  • postOp(mode, context, actualGasCost, actualUserOpFeePerGas)

  • _postOp(, , , )

  • deposit()

  • withdraw(to, value)

  • addStake(unstakeDelaySec)

  • unlockStake()

  • withdrawStake(to)

  • _checkEntryPoint()

  • _authorizeWithdraw()

EIP712
  • _domainSeparatorV4()

  • _hashTypedDataV4(structHash)

  • eip712Domain()

  • _EIP712Name()

  • _EIP712Version()

AbstractSigner
  • _rawSignatureValidation(hash, signature)

Events
IERC5267
  • EIP712DomainChanged()

Errors
PaymasterCore
  • PaymasterUnauthorized(sender)

_signableUserOpHash(struct PackedUserOperation userOp, uint48 validAfter, uint48 validUntil) → bytes32 internal

Virtual function that returns the signable hash for a user operations. Given the userOpHash contains the paymasterAndData itself, it’s not possible to sign that value directly. Instead, this function must be used to provide a custom mechanism to authorize an user operation.

_validatePaymasterUserOp(struct PackedUserOperation userOp, bytes32, uint256) → bytes context, uint256 validationData internal

Internal validation of whether the paymaster is willing to pay for the user operation. Returns the context to be passed to postOp and the validation data.

The context returned is bytes(0). Developers overriding this function MUST override _postOp to process the context passed along.

_decodePaymasterUserOp(struct PackedUserOperation userOp) → uint48 validAfter, uint48 validUntil, bytes signature internal

Decodes the user operation’s data from paymasterAndData.