diff --git a/src/interfaces/IExecutionHookModule.sol b/src/interfaces/IExecutionHookModule.sol index 501889f3..17db8dc2 100644 --- a/src/interfaces/IExecutionHookModule.sol +++ b/src/interfaces/IExecutionHookModule.sol @@ -10,7 +10,7 @@ interface IExecutionHookModule is IModule { /// be more than one. /// @param sender The caller address. /// @param value The call value. - /// @param data The calldata sent. + /// @param data The calldata sent. For `executeUserOp` calls, hook modules should receive the full msg.data. /// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned. function preExecutionHook(uint32 entityId, address sender, uint256 value, bytes calldata data) external diff --git a/src/interfaces/IModularAccount.sol b/src/interfaces/IModularAccount.sol index e553782f..0eedcd4e 100644 --- a/src/interfaces/IModularAccount.sol +++ b/src/interfaces/IModularAccount.sol @@ -66,10 +66,10 @@ interface IModularAccount { /// @return An array containing the return data from the calls. function executeBatch(Call[] calldata calls) external payable returns (bytes[] memory); - /// @notice Execute a call using a specified runtime validation. + /// @notice Execute a call using the specified runtime validation. /// @param data The calldata to send to the account. - /// @param authorization The authorization data to use for the call. The first 24 bytes specifies which runtime - /// validation to use, and the rest is sent as a parameter to runtime validation. + /// @param authorization The authorization data to use for the call. The first 24 bytes is a ModuleEntity which + /// specifies which runtime validation to use, and the rest is sent as a parameter to runtime validation. function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization) external payable @@ -77,23 +77,29 @@ interface IModularAccount { /// @notice Install a module to the modular account. /// @param module The module to install. - /// @param manifest the manifest describing functions to install - /// @param moduleInstallData Optional data to be used by the account to handle the initial execution setup, - /// data encoding is implementation-specific. - function installExecution( - address module, - ExecutionManifest calldata manifest, - bytes calldata moduleInstallData - ) external; + /// @param manifest the manifest describing functions to install. + /// @param installData Optional data to be used by the account to handle the initial execution setup. Data + /// encoding + /// is implementation-specific. + function installExecution(address module, ExecutionManifest calldata manifest, bytes calldata installData) + external; + + /// @notice Uninstall a module from the modular account. + /// @param module The module to uninstall. + /// @param manifest the manifest describing functions to uninstall. + /// @param uninstallData Optional data to be used by the account to handle the execution uninstallation. Data + /// encoding is implementation-specific. + function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData) + external; /// @notice Installs a validation function across a set of execution selectors, and optionally mark it as a - /// global validation. + /// global validation function. /// @dev This does not validate anything against the manifest - the caller must ensure validity. /// @param validationConfig The validation function to install, along with configuration flags. /// @param selectors The selectors to install the validation function for. - /// @param installData Optional data to be used by the account to handle the initial validation setup, data + /// @param installData Optional data to be used by the account to handle the initial validation setup. Data /// encoding is implementation-specific. - /// @param hooks Optional hooks to install and associate with the validation function, data encoding is + /// @param hooks Optional hooks to install and associate with the validation function. Data encoding is /// implementation-specific. function installValidation( ValidationConfig validationConfig, @@ -104,27 +110,17 @@ interface IModularAccount { /// @notice Uninstall a validation function from a set of execution selectors. /// @param validationFunction The validation function to uninstall. - /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation, data - /// encoding is implementation-specific. - /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation, data + /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation. Data /// encoding is implementation-specific. + /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation. Data + /// encoding + /// is implementation-specific. function uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, bytes[] calldata hookUninstallData ) external; - /// @notice Uninstall a module from the modular account. - /// @param module The module to uninstall. - /// @param manifest the manifest describing functions to uninstall. - /// @param moduleUninstallData Optional data to be used by the account to handle the execution uninstallation, - /// data encoding is implementation-specific. - function uninstallExecution( - address module, - ExecutionManifest calldata manifest, - bytes calldata moduleUninstallData - ) external; - /// @notice Return a unique identifier for the account implementation. /// @dev This function MUST return a string in the format "vendor.account.semver". The vendor and account /// names MUST NOT contain a period character. diff --git a/src/interfaces/IModularAccountView.sol b/src/interfaces/IModularAccountView.sol index 3541688b..02046295 100644 --- a/src/interfaces/IModularAccountView.sol +++ b/src/interfaces/IModularAccountView.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {HookConfig, ModuleEntity} from "../interfaces/IModularAccount.sol"; -// Represents data associated with a specifc function selector. +/// @dev Represents data associated with a specific function selector. struct ExecutionDataView { // The module that implements this execution function. // If this is a native function, the address must remain address(0). @@ -20,9 +20,9 @@ struct ExecutionDataView { } struct ValidationDataView { - // Whether or not this validation can be used as a global validation function. + // Whether or not this validation function can be used as a global validation function. bool isGlobal; - // Whether or not this validation is a signature validator. + // Whether or not this validation function is a signature validator. bool isSignatureValidation; // Whether or not this validation is a user operation validator. bool isUserOpValidation; @@ -38,13 +38,13 @@ interface IModularAccountView { /// @notice Get the execution data for a selector. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param selector The selector to get the data for. - /// @return ExecutionData The module address for this selector. + /// @return The execution data for this selector. function getExecutionData(bytes4 selector) external view returns (ExecutionDataView memory); - /// @notice Get the validation data for a validation. + /// @notice Get the validation data for a validation function. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param validationFunction The validation function to get the data for. - /// @return ValidationData The module address for this selector. + /// @return The validation data for this validation function. function getValidationData(ModuleEntity validationFunction) external view diff --git a/src/interfaces/IValidationModule.sol b/src/interfaces/IValidationModule.sol index f0224e26..c8c47ede 100644 --- a/src/interfaces/IValidationModule.sol +++ b/src/interfaces/IValidationModule.sol @@ -42,7 +42,7 @@ interface IValidationModule is IModule { /// @param sender the address that sent the ERC-1271 request to the smart account /// @param hash the hash of the ERC-1271 request /// @param signature the signature of the ERC-1271 request - /// @return the ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid. + /// @return The ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid. function validateSignature( address account, uint32 entityId, diff --git a/standard/ERCs/erc-6900.md b/standard/ERCs/erc-6900.md index c400df5a..8625453a 100644 --- a/standard/ERCs/erc-6900.md +++ b/standard/ERCs/erc-6900.md @@ -1,7 +1,7 @@ --- eip: 6900 -title: Modular Smart Contract Accounts and Modules -description: Interfaces for composable contract accounts optionally supporting upgradability and introspection +title: Modular Smart Contract Accounts +description: Interfaces for smart contract accounts and modules, optionally supporting upgradability and introspection author: Adam Egyed (@adamegyed), Fangting Liu (@trinity-0111), Jay Paik (@jaypaik), Yoav Weiss (@yoavw), Huawei Gu (@huaweigu), Daniel Lim (@dlim-circle), Zhiyu Zhang (@ZhiyuCircle), Ruben Koch (@0xrubes), David Philipson (@dphilipson), Howy Ho (@howydev) discussions-to: https://ethereum-magicians.org/t/eip-modular-smart-contract-accounts-and-plugins/13885 status: Draft @@ -13,7 +13,7 @@ requires: 165, 1271, 4337 ## Abstract -This proposal standardizes smart contract accounts and account modules, which are smart contract interfaces that allow for composable logic within smart contract accounts. This proposal is compliant with [ERC-4337](./eip-4337.md). This standard emphasizes secure permissioning of modules, and maximal interoperability between all spec-compliant accounts and modules. +This proposal standardizes smart contract accounts and account modules, which are smart contracts that allow for composable logic within smart contract accounts. This proposal is compliant with [ERC-4337](./eip-4337.md). This standard emphasizes secure permissioning of modules, and maximal interoperability between all spec-compliant accounts and modules. This modular approach splits account functionality into three categories, implements them in external contracts, and defines an expected execution flow from accounts. @@ -23,9 +23,9 @@ One of the goals that ERC-4337 accomplishes is abstracting the logic for executi Many new features of accounts can be built by customizing the logic that goes into the validation and execution steps. Examples of such features include session keys, subscriptions, spending limits, and role-based access control. Currently, some of these features are implemented natively by specific smart contract accounts, and others are able to be implemented by proprietary module systems like Safe modules. -However, managing multiple account instances provides a worse user experience, fragmenting accounts across supported features and security configurations. Additionally, it requires module developers to choose which platforms to support, causing either platform lock-in or duplicated development effort. +However, managing multiple account implementations provides a poor user experience, fragmenting accounts across supported features and security configurations. Additionally, it requires module developers to choose which platforms to support, causing either platform lock-in or duplicated development effort. -We propose a standard that coordinates the implementation work between module developers and wallet developers. This standard defines a modular smart contract account capable of supporting all standard-conformant modules. This allows users to have greater portability of their data, and for module developers to not have to choose specific account implementations to support. +We propose a standard that coordinates the implementation work between module developers and account developers. This standard defines a modular smart contract account capable of supporting all standard-conformant modules. This allows users to have greater portability of their data, and for module developers to not have to choose specific account implementations to support. ![diagram showing relationship between accounts and modules with modular functions](../assets/eip-6900/MSCA_Shared_Components_Diagram.svg) @@ -44,58 +44,58 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S - **Validation functions** validate authorization on behalf of the account. - **Execution functions** execute custom logic allowed by the account. - **Hooks** execute custom logic and checks before and/or after an execution function or validation function. There are two types of hooks: - - **Validation hook** functions run before a validation function. These can enforce permissions on actions authorized by a validation function. - - **Execution hook** functions can run before and/or after an execution function. Hooks can be attached either to a specific execution function selector, or a validation function. A pre execution hook may optionally return data to be consumed by a post execution hook function. + - **Validation hooks** run before a validation function. These can enforce permissions on actions authorized by a validation function. + - **Execution hooks** can run before and/or after an execution function. Execution hooks can be attached either to a specific execution function or a validation function. A pre execution hook may optionally return data to be consumed by a post execution hook. - A **native function** refers to a function implemented by the modular account, as opposed to a function added by a module. - A **module** is a deployed smart contract that hosts any amount of the above three kinds of modular functions. -- A module **manifest** describes the execution functions, interface ids, and hooks that should be installed on the account. +- A module's **manifest** describes the execution functions, interface IDs, and hooks that should be installed on the account. ### Overview -A modular account handles two kinds of calls: either from the `Entrypoint` through ERC-4337, or through direct calls from externally owned accounts (EOAs) and other smart contracts. This standard supports both use cases. +A modular account handles two kinds of calls: either from the `EntryPoint` through ERC-4337, or through direct calls from externally owned accounts (EOAs) and other smart contracts. This standard supports both use cases. -A call to the smart contract account can be broken down into the steps as shown in the diagram below. The validation steps validate if the caller is allowed to perform the call. The pre execution hook step can be used to do any pre execution checks or updates. It can also be used along with the post execution hook step to perform additional actions or verification. The execution step performs a defined task or collection of tasks. +A call to the modular account can be broken down into the steps as shown in the diagram below. The validation steps validate if the caller is allowed to perform the call. The pre execution hook step can be used to do any pre execution checks or updates. It can also be used along with the post execution hook step to perform additional actions or verification. The execution step performs a defined task or collection of tasks. -![diagram showing call flow within an modular account](../assets/eip-6900/Modular_Account_Call_Flow.svg) +![diagram showing call flow within a modular account](../assets/eip-6900/Modular_Account_Call_Flow.svg) -Each step is modular, supporting different implementations, that allows for open-ended programmable accounts. +Each step is modular, supporting different implementations, which allows for open-ended programmable accounts. ### Interfaces -**Modular Smart Contract Accounts** **MUST** implement +Modular accounts MUST implement: - `IAccount.sol` and `IAccountExecute.sol` from [ERC-4337](./eip-4337.md). - `IModularAccount.sol` to support module management and usage, and account identification. - The function `isValidSignature` from [ERC-1271](./eip-1271.md) -**Modular Smart Contract Accounts** **MAY** implement +Modular accounts MAY implement: - `IModularAccountView.sol` to support visibility in account states on-chain. - [ERC-165](./eip-165.md) for interfaces installed from modules. -**Modules** **MUST** implement +Modules MUST implement: - `IModule.sol` described below and implement ERC-165 for `IModule`. -**Modules** **MAY** implement any of the following module types +Modules MAY implement any of the following module types: -- `IValidationModule` to support validations for account. -- `IValidationHookModule` to support hooks for validations. -- `IExecutionModule` to support execution functions and their installations on account. +- `IValidationModule` to support validation functions for the account. +- `IValidationHookModule` to support hooks for validation functions. +- `IExecutionModule` to support execution functions and their installations on the account. - `IExecutionHookModule` to support pre & post execution hooks for execution functions. #### `IModularAccount.sol` -Module execution and management interface. Modular Smart Contract Accounts **MUST** implement this interface to support installing and uninstalling modules, and open-ended execution. +Module execution and management interface. Modular accounts MUST implement this interface to support installing and uninstalling modules, and open-ended execution. ```solidity -/// A packed representation of a module function. +/// @dev A packed representation of a module function. /// Consists of the following, left-aligned: /// Module address: 20 bytes /// Entity ID: 4 bytes type ModuleEntity is bytes24; -/// A packed representation of a validation function and its associated flags. +/// @dev A packed representation of a validation function and its associated flags. /// Consists of the following, left-aligned: /// Module address: 20 bytes /// Entity ID: 4 bytes @@ -108,7 +108,7 @@ type ModuleEntity is bytes24; /// 0b_______C // isUserOpValidation type ValidationConfig is bytes25; -/// A packed representation of a hook function and its associated flags. +/// @dev A packed representation of a hook function and its associated flags. /// Consists of the following, left-aligned: /// Module address: 20 bytes /// Entity ID: 4 bytes @@ -150,10 +150,10 @@ interface IModularAccount { /// @return An array containing the return data from the calls. function executeBatch(Call[] calldata calls) external payable returns (bytes[] memory); - /// @notice Execute a call using a specified runtime validation. + /// @notice Execute a call using the specified runtime validation. /// @param data The calldata to send to the account. - /// @param authorization The authorization data to use for the call. The first 24 bytes specifies which runtime - /// validation to use, and the rest is sent as a parameter to runtime validation. + /// @param authorization The authorization data to use for the call. The first 24 bytes is a ModuleEntity which + /// specifies which runtime validation to use, and the rest is sent as a parameter to runtime validation. function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization) external payable @@ -162,22 +162,33 @@ interface IModularAccount { /// @notice Install a module to the modular account. /// @param module The module to install. /// @param manifest the manifest describing functions to install. - /// @param moduleInstallData Optional data to be used by the account to handle the initial execution setup, - /// data encoding is implementation-specific. + /// @param installData Optional data to be used by the account to handle the initial execution setup. Data encoding + /// is implementation-specific. function installExecution( address module, ExecutionManifest calldata manifest, - bytes calldata moduleInstallData + bytes calldata installData + ) external; + + /// @notice Uninstall a module from the modular account. + /// @param module The module to uninstall. + /// @param manifest the manifest describing functions to uninstall. + /// @param uninstallData Optional data to be used by the account to handle the execution uninstallation. Data + /// encoding is implementation-specific. + function uninstallExecution( + address module, + ExecutionManifest calldata manifest, + bytes calldata uninstallData ) external; /// @notice Installs a validation function across a set of execution selectors, and optionally mark it as a - /// global validation. + /// global validation function. /// @dev This does not validate anything against the manifest - the caller must ensure validity. /// @param validationConfig The validation function to install, along with configuration flags. /// @param selectors The selectors to install the validation function for. - /// @param installData Optional data to be used by the account to handle the initial validation setup, data + /// @param installData Optional data to be used by the account to handle the initial validation setup. Data /// encoding is implementation-specific. - /// @param hooks Optional hooks to install and associate with the validation function, data encoding is + /// @param hooks Optional hooks to install and associate with the validation function. Data encoding is /// implementation-specific. function installValidation( ValidationConfig validationConfig, @@ -188,9 +199,9 @@ interface IModularAccount { /// @notice Uninstall a validation function from a set of execution selectors. /// @param validationFunction The validation function to uninstall. - /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation, data + /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation. Data /// encoding is implementation-specific. - /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation, data encoding + /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation. Data encoding /// is implementation-specific. function uninstallValidation( ModuleEntity validationFunction, @@ -198,17 +209,6 @@ interface IModularAccount { bytes[] calldata hookUninstallData ) external; - /// @notice Uninstall a module from the modular account. - /// @param module The module to uninstall. - /// @param manifest the manifest describing functions to uninstall. - /// @param moduleUninstallData Optional data to be used by the account to handle the execution uninstallation, data - /// encoding is implementation-specific. - function uninstallExecution( - address module, - ExecutionManifest calldata manifest, - bytes calldata moduleUninstallData - ) external; - /// @notice Return a unique identifier for the account implementation. /// @dev This function MUST return a string in the format "vendor.account.semver". The vendor and account /// names MUST NOT contain a period character. @@ -219,10 +219,10 @@ interface IModularAccount { #### `IModularAccountView.sol` -Module inspection interface. Modular Smart Contract Accounts **MAY** implement this interface to support visibility in module configuration. +Module inspection interface. Modular accounts MAY implement this interface to support visibility in module configuration. ```solidity -// Represents data associated with a specifc function selector. +/// @dev Represents data associated with a specific function selector. struct ExecutionDataView { // The module that implements this execution function. // If this is a native function, the address must remain address(0). @@ -239,9 +239,9 @@ struct ExecutionDataView { } struct ValidationDataView { - // Whether or not this validation can be used as a global validation function. + // Whether or not this validation function can be used as a global validation function. bool isGlobal; - // Whether or not this validation is a signature validator. + // Whether or not this validation function is a signature validator. bool isSignatureValidation; // The pre validation hooks for this validation function. ModuleEntity[] preValidationHooks; @@ -255,13 +255,13 @@ interface IModularAccountView { /// @notice Get the execution data for a selector. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param selector The selector to get the data for. - /// @return ExecutionData The module address for this selector. + /// @return The execution data for this selector. function getExecutionData(bytes4 selector) external view returns (ExecutionDataView memory); - /// @notice Get the validation data for a validation. + /// @notice Get the validation data for a validation function. /// @dev If the selector is a native function, the module address will be the address of the account. /// @param validationFunction The validation function to get the data for. - /// @return ValidationData The module address for this selector. + /// @return The validation data for this validation function. function getValidationData(ModuleEntity validationFunction) external view @@ -271,7 +271,7 @@ interface IModularAccountView { #### `IModule.sol` -Module interface. Modules **MUST** implement this interface to support module management and interactions with ERC-6900 modular accounts. +Module interface. Modules MUST implement this interface to support module management and interactions with ERC-6900 modular accounts. ```solidity interface IModule is IERC165 { @@ -297,7 +297,7 @@ interface IModule is IERC165 { #### `IValidationModule.sol` -Validation module interface. Modules **MAY** implement this interface to provide validation functions for account. +Validation module interface. Modules MAY implement this interface to provide validation functions for the account. ```solidity interface IValidationModule is IModule { @@ -337,7 +337,7 @@ interface IValidationModule is IModule { /// @param sender the address that sent the ERC-1271 request to the smart account /// @param hash the hash of the ERC-1271 request /// @param signature the signature of the ERC-1271 request - /// @return the ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid. + /// @return The ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid. function validateSignature( address account, uint32 entityId, @@ -350,7 +350,7 @@ interface IValidationModule is IModule { #### `IValidationHookModule.sol` -Validation hook module interface. Modules **MAY** implement this interface to provide hooks for validation functions for account. +Validation hook module interface. Modules MAY implement this interface to provide hooks for validation functions for the account. ```solidity interface IValidationHookModule is IModule { @@ -396,7 +396,7 @@ interface IValidationHookModule is IModule { #### `IExecutionModule.sol` -Execution module interface. Modules **MAY** implement this interface to provide execution functions for account. +Execution module interface. Modules MAY implement this interface to provide execution functions for the account. ```solidity struct ManifestExecutionFunction { @@ -435,7 +435,7 @@ interface IExecutionModule is IModule { #### `IExecutionHookModule.sol` -Execution hook module interface. Modules **MAY** implement this interface to provide hooks for execution functions for account. +Execution hook module interface. Modules MAY implement this interface to provide hooks for execution functions for the account. ```solidity interface IExecutionHookModule is IModule { @@ -460,58 +460,59 @@ interface IExecutionHookModule is IModule { } ``` -### Validations and Their Installation/Uninstallation +### Validation Functions and Their Installation/Uninstallation -An account can have more than one validation module/function installed. -An account can have the same validation module installed more than once. -The entityId of a validation function installed on an account MUST be unique. -Validation installation MAY be deferred until a later time, such as upon first use. +- An account can have more than one validation module/function installed. +- An account can have the same validation module installed more than once. +- The entity ID of a validation function installed on an account MUST be unique. +- Validation installation MAY be deferred until a later time, such as upon first use. #### Installation During validation installation, the account MUST correctly set flags and other fields based on the incoming data provided by the user. -- the account MUST install all pre validation hooks required by the user and SHOULD call `onInstall` with the user-provided data on the hook module to initialize the states if required by user. -- the account MUST install all execution hooks required by the user and SHOULD call `onInstall` with the user-provided data on the hook module to initialize the states if required by user. -- the account MUST add all selectors required by the user that the validation can validate. -- the account MUST set all flags as required, like `isGlobal`, `isSignatureValidation`, and `isUserOpValidation`. -- the account SHOULD call `onInstall` on the validation module to initialize the states if required by user. -- the account MUST emit `ValidationInstalled` as defined in the interface for all installed validations. +- The account MUST install all validation hooks specified by the user and SHOULD call `onInstall` with the user-provided data on the hook module to initialize state if specified by the user. +- The account MUST install all execution hooks specified by the user and SHOULD call `onInstall` with the user-provided data on the hook module to initialize state if specified by the user. +- The account MUST configure the validation function to validate all of the selectors specified by the user. +- The account MUST set all flags as specified, like `isGlobal`, `isSignatureValidation`, and `isUserOpValidation`. +- The account SHOULD call `onInstall` on the validation module to initialize state if specified by the user. +- The account MUST emit `ValidationInstalled` as defined in the interface for all installed validation functions. #### Uninstallation During validation uninstallation, the account MUST correctly clear flags and other fields based on the incoming data provided by the user. -- the account MUST clear all flags for the validation function, like `isGlobal`, `isSignatureValidation`, and `isUserOpValidation`. -- the account MUST remomve all hooks and SHOULD clear hook module states by calling `onUninstall` with the user-provided data for each hook, including both pre validation hooks and execution hooks, if required by user. -- the account MUST remove all selectors that the validation function can validate. -- the account MUST emit `ValidationUninstalled` as defined in the interface for all uninstalled validations. +- The account MUST clear all flags for the validation function, like `isGlobal`, `isSignatureValidation`, and `isUserOpValidation`. +- The account MUST remove all hooks and SHOULD clear hook module states by calling `onUninstall` with the user-provided data for each hook, including both validation hooks and execution hooks, if specified by the user. +- The account MUST clear the configuration for the selectors that the validation function can validate. +- The account SHOULD call `onUninstall` on the validation module to clean up state if specified by the user. +- The account MUST emit `ValidationUninstalled` as defined in the interface for all uninstalled validation functions. -### Execution and Their Installation/Uninstallation +### Execution Functions and Their Installation/Uninstallation -An account can install any number of execution functions. -An execution function selector MUST be unique in the account. -An execution function selector MUST not conflict with native ERC-4337 and ERC-6900 functions. +- An account can install any number of execution functions. +- An execution function selector MUST be unique in the account. +- An execution function selector MUST not conflict with native ERC-4337 and ERC-6900 functions. #### Installation During execution installation, the account MUST correctly set flags and other fields based on the incoming data and module manifest provided by the user. -- the account MUST install all execution functions and set flags and fields as specified in the manifest. -- the account MUST add all execution hooks as specified in the manifest. -- the account SHOULD add all supported interfaces as specified in the manifest. -- the account SHOULD call `onInstall` on the execution module to initialize the states if required by user. -- the account MUST emit `ExecutionInstalled` as defined in the interface for all installed executions. +- The account MUST install all execution functions and set flags and fields as specified in the manifest. +- The account MUST add all execution hooks as specified in the manifest. +- The account SHOULD add all supported interfaces as specified in the manifest. +- The account SHOULD call `onInstall` on the execution module to initialize state if specified by the user. +- The account MUST emit `ExecutionInstalled` as defined in the interface for all installed executions. #### Uninstallation During execution uninstallation, the account MUST correctly clear flags and other fields based on the incoming data and module manifest provided by the user. -- the account MUST remove all execution functions and clear flags and fields as specified in the manifest. -- the account MUST remove all execution hooks as specified in the manifest. -- the account MUST remove all supported interfaces as specified in the manifest. -- the account SHOULD call `onUnInstall` on the execution module to initialize the states and track call success if required by user. -- the account MUST emit `ExecutionUninstalled` as defined in the interface for all uninstalled executions. +- The account MUST remove all execution functions and clear flags and fields as specified in the manifest. +- The account MUST remove all execution hooks as specified in the manifest. +- The account SHOULD remove all supported interfaces as specified in the manifest. +- The account SHOULD call `onUninstall` on the execution module to clean up state and track call success if specified by the user. +- The account MUST emit `ExecutionUninstalled` as defined in the interface for all uninstalled executions. ### Hooks @@ -530,11 +531,11 @@ It is RECOMMENDED that an account implementer runs hooks in first installed firs ### Validation Call Flow -Modular accounts support three different calls flows for validation: user op validation, runtime validation, and signature validation. User op validation happens within the account's implementation of the function `validateUserOp`, defined in the ERC-4337 interface `IAccount`. Runtime validation happens through the dispatcher function `executeWithRuntimeValidation`, or when using direct call validation. Signature validation happens within the account's implementation of the function `isValidSignature`, defined in ERC-1271. +Modular accounts support three different calls flows for validation: user op validation, runtime validation, and signature validation. User op validation happens within the account's implementation of the function `validateUserOp`, defined in the ERC-4337 interface `IAccount`. Runtime validation happens through the dispatcher function `executeWithRuntimeValidation`, or when using [direct call validation](#direct-call-validation). Signature validation happens within the account's implementation of the function `isValidSignature`, defined in ERC-1271. For each of these validation types, an account implementation MAY specify its own format for selecting which validation function to use, as well as any per-hook data for validation hooks. -Within the implementation of each type of validation function, the modular account MUST check that the provided validation function applies to the given function selector intended to be run. Then, the account MUST execute all validation hooks of the corresponding type associated with the validation function in use. After the execution of validation hooks, the account MUST invoke the validation function of the corresponding type. If any validation hooks or the validation function revert, the account MUST revert. It SHOULD include the module's revert data within its revert data. +Within the implementation of each type of validation function, the modular account MUST check that the provided validation function applies to the given function selector intended to be run (See [Checking Validation Applicability](#checking-validation-applicability)). Then, the account MUST execute all validation hooks of the corresponding type associated with the validation function in use. After the execution of validation hooks, the account MUST invoke the validation function of the corresponding type. If any of the validation hooks or the validation function reverts, the account MUST revert. It SHOULD include the module's revert data within its revert data. The account MUST define a way to pass data separately for each validation hook and the validation function itself. This data MUST be sent as the `userOp.signature` field for user op validation, the `authorization` field for runtime validation, and the `signature` field for signature validation. @@ -546,23 +547,23 @@ The set of validation hooks run MUST be the hooks specified by account state at To enforce module permission isolation, the modular account MUST check validation function applicability as part of each validation function implementation. -User op validation and runtime validation functions have a configurable range of applicability to functions on the account. This can be configured with selectors installed to a validation. Alternatively, a validation installation may specify the `isGlobal` flag as true, which means the account MUST consider it applicable to any module execution function with the `allowGlobalValidation` flag set to true, or for any account native function that the account MAY allow for global validation. +User op validation and runtime validation functions have a configurable range of applicability to functions on the account. This can be configured with selectors installed to a validation. Alternatively, a validation installation MAY specify the `isGlobal` flag as true, which means the account MUST consider it applicable to any module execution function with the `allowGlobalValidation` flag set to true, or for any account native function that the account MAY allow for global validation. -If the selector being checked is `execute` or `executeBatch`, the modular account MUST perform additional checking. If the target of `execute` is the modular account's own address, or if the target of any `Call` within `executeBatch` is the account, validation MUST either revert, or check that validation applies to the selector(s) being called. +If the selector being checked is `execute` or `executeBatch`, the modular account MUST perform additional checking. If the target of `execute` is the modular account's own address, or if the target of any `Call` within `executeBatch` is the account, validation MUST either revert or check that validation applies to the selector(s) being called. -Installed validations have two flag variables indicating what they may be used for. If a validation is attempted to be used for user op validation and the flag `isUserOpValidation` is set to false, validation MUST revert. If the validation is attempted to be used for signature validation and the flag `isSignatureValidation` is set to false, validation MUST revert. +Installed validation functions have two flag variables indicating what they may be used for. If a validation function is attempted to be used for user op validation and the flag `isUserOpValidation` is set to false, validation MUST revert. If the validation function is attempted to be used for signature validation and the flag `isSignatureValidation` is set to false, validation MUST revert. #### Direct Call Validation If a validation function is installed with the entity ID of `0xffffffff`, it may be used as direct call validation. This occurs when a module or other address calls a function on the modular account, without wrapping its call in the dispatcher function `executeWithRuntimeValidation` to use as a selection mechanism for a runtime validation function. -To implement direct call validation, the modular account MUST treat direct function calls that are not from the modular account itself or the EntryPoint as an attempt to validate using the caller's address and the entity ID of `0xffffffff`. If such a validation function is installed, and applies to the function intended to be called, the modular account MUST allow it to continue, without performing runtime validation. Any pre validation hooks and execution hooks installed to this validation function MUST still run. +To implement direct call validation, the modular account MUST treat direct function calls that are not from the modular account itself or the `EntryPoint` as an attempt to validate using the caller's address and the entity ID of `0xffffffff`. If such a validation function is installed, and applies to the function intended to be called, the modular account MUST allow it to continue, without performing runtime validation. Any validation hooks and execution hooks installed to this validation function MUST still run. ### Execution Call Flow For all non-view functions within `IModularAccount` except `executeWithRuntimeValidation`, all module-defined execution functions, and any additional native functions that the modular account MAY wish to include, the modular account MUST adhere to these steps during execution: -If the caller is not the EntryPoint or the account, the account MUST check access control for direct call validation. +If the caller is not the `EntryPoint` or the account, the account MUST check access control for direct call validation. Prior to running the target function, the modular account MUST run all pre execution hooks that apply for the current function call. Pre execution hooks apply if they have been installed to the currently running function selector, or if they are installed as an execution hook to the validation function that was used for the current execution. Pre execution hooks MUST run validation-associated hooks first, then selector-associated hooks second. @@ -572,7 +573,7 @@ After the execution of the target function, the modular account MUST run any pos The set of hooks run for a given target function MUST be the hooks specified by account state at the start of the execution phase. In other words, if the set of applicable hooks changes during execution, the original set of hooks MUST still run, and only future invocations of the same target function should reflect the changed set of hooks. -Module execution functions where the field `skipRuntimeValidation` is set to true, or native functions without access control, SHOULD omit the runtime validation step, including any runtime validation hooks. Native functions without access control MAY also omit running execution hooks. +Module execution functions where the field `skipRuntimeValidation` is set to true, as well as native functions without access control, SHOULD omit the runtime validation step, including any runtime validation hooks. Native functions without access control MAY also omit running execution hooks. ### Extension