diff --git a/src/account/ModuleManagerInternals.sol b/src/account/ModuleManagerInternals.sol index ee42012d..04130e41 100644 --- a/src/account/ModuleManagerInternals.sol +++ b/src/account/ModuleManagerInternals.sol @@ -286,7 +286,7 @@ abstract contract ModuleManagerInternals is IModularAccount { revert ArrayLengthMismatch(); } - // Hook uninstall data is provided in the order of pre-validation hooks, then permission hooks. + // Hook uninstall data is provided in the order of pre validation hooks, then permission hooks. uint256 hookIndex = 0; for (uint256 i = 0; i < _validationData.preValidationHooks.length; ++i) { bytes calldata hookData = hookUninstallDatas[hookIndex]; diff --git a/src/account/ReferenceModularAccount.sol b/src/account/ReferenceModularAccount.sol index cefc1d46..9be42767 100644 --- a/src/account/ReferenceModularAccount.sol +++ b/src/account/ReferenceModularAccount.sol @@ -442,7 +442,7 @@ contract ReferenceModularAccount is } } - // Run the pre hooks and copy their return data to the post hooks array, if an associated post-exec hook + // Run the pre hooks and copy their return data to the post hooks array, if an associated post exec hook // exists. for (uint256 i = 0; i < hooksLength; ++i) { HookConfig hookConfig = toHookConfig(executionHooks.at(i)); @@ -452,7 +452,7 @@ contract ReferenceModularAccount is preExecHookReturnData = _runPreExecHook(hookConfig.moduleEntity(), data); - // If there is an associated post-exec hook, save the return data. + // If there is an associated post exec hook, save the return data. if (hookConfig.hasPostHook()) { postHooksToRun[i].preExecHookReturnData = preExecHookReturnData; } @@ -523,15 +523,15 @@ contract ReferenceModularAccount is /** * Order of operations: * 1. Check if the sender is the entry point, the account itself, or the selector called is public. - * - Yes: Return an empty array, there are no post-permissionHooks. + * - Yes: Return an empty array, there are no post permissionHooks. * - No: Continue * 2. Check if the called selector (msg.sig) is included in the set of selectors the msg.sender can * directly call. * - Yes: Continue * - No: Revert, the caller is not allowed to call this selector * 3. If there are runtime validation hooks associated with this caller-sig combination, run them. - * 4. Run the pre-permissionHooks associated with this caller-sig combination, and return the - * post-permissionHooks to run later. + * 4. Run the pre permissionHooks associated with this caller-sig combination, and return the + * post permissionHooks to run later. */ function _checkPermittedCallerAndAssociatedHooks() internal diff --git a/src/helpers/Constants.sol b/src/helpers/Constants.sol index 4ad649c1..c65dc33d 100644 --- a/src/helpers/Constants.sol +++ b/src/helpers/Constants.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.25; // Index marking the start of the data for the validation function. uint8 constant RESERVED_VALIDATION_DATA_INDEX = type(uint8).max; -// Maximum number of pre-validation hooks that can be registered. +// Maximum number of pre validation hooks that can be registered. uint8 constant MAX_PRE_VALIDATION_HOOKS = type(uint8).max; // Magic value for the Entity ID of direct call validation. diff --git a/src/interfaces/IModularAccount.sol b/src/interfaces/IModularAccount.sol index 8ddebb75..6ce78d44 100644 --- a/src/interfaces/IModularAccount.sol +++ b/src/interfaces/IModularAccount.sol @@ -65,7 +65,7 @@ interface IModularAccount { /// @param selectors The selectors to install the validation function for. /// @param installData Optional data to be decoded and used by the module to setup initial module state. /// @param hooks Optional hooks to install, associated with the validation function. These may be - /// pre-validation hooks or execution hooks. The expected format is a bytes26 HookConfig, followed by the + /// pre validation hooks or execution hooks. The expected format is a bytes26 HookConfig, followed by the /// install data, if any. function installValidation( ValidationConfig validationConfig, @@ -79,8 +79,8 @@ interface IModularAccount { /// @param uninstallData Optional data to be decoded and used by the module to clear module data for the /// account. /// @param hookUninstallData Optional data to be used by hooks for cleanup. If any are provided, the array must - /// be of a length equal to existing pre-validation hooks plus permission hooks. Hooks are indexed by - /// pre-validation hook order first, then permission hooks. + /// be of a length equal to existing pre validation hooks plus permission hooks. Hooks are indexed by + /// pre validation hook order first, then permission hooks. function uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, diff --git a/standard/ERCs/erc-6900.md b/standard/ERCs/erc-6900.md index 933296ca..86ac92ea 100644 --- a/standard/ERCs/erc-6900.md +++ b/standard/ERCs/erc-6900.md @@ -13,7 +13,7 @@ requires: 165, 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), and takes inspiration from [ERC-2535](./eip-2535.md) when defining interfaces for updating and querying modular function implementations. +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 modular approach splits account functionality into three categories, implements them in external contracts, and defines an expected execution flow from accounts. @@ -21,7 +21,7 @@ This modular approach splits account functionality into three categories, implem One of the goals that ERC-4337 accomplishes is abstracting the logic for execution and validation to each smart contract account. -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 module systems. Examples of proprietary module systems include Safe modules and ZeroDev modules. +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. @@ -29,17 +29,10 @@ We propose a standard that coordinates the implementation work between module de ![diagram showing relationship between accounts and modules with modular functions](../assets/eip-6900/MSCA_Shared_Components_Diagram.svg) -We take inspiration from ERC-2535's diamond pattern for routing execution based on function selectors, and create a similarly composable account. However, the standard does not require the multi-facet proxy pattern. - -These modules can contain execution logic, validation schemes, and hooks. Validation schemes define the circumstances under which the smart contract account will approve actions taken on its behalf, while hooks allow for pre- and post-execution controls. +These modules can contain execution logic, validation functions, and hooks. Validation functions define the circumstances under which the smart contract account will approve actions taken on its behalf, while hooks allow for pre and post execution controls. Accounts adopting this standard will support modular, upgradable execution and validation logic. Defining this as a standard for smart contract accounts will make modules easier to develop securely and will allow for greater interoperability. -Goals: - -- Provide standards for how validation, execution, and hook functions for smart contract accounts should be written. -- Provide standards for how compliant accounts should add, update, remove, and inspect modules. - ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. @@ -48,23 +41,15 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S - An **account** (or **smart contract account, SCA**) is a smart contract that can be used to send transactions and hold digital assets. It implements the `IAccount` interface from ERC-4337. - A **modular account** (or **modular smart contract account, MSCA**) is an account that supports modular functions. There are three types of modular functions: - - **Validation functions** validate the caller's authenticity and authority to the account. - - **Execution functions** execute any custom logic allowed by the account. + - **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. -- A **validation function** is a function that validates authentication and authorization of a caller to the account. There are two types of validation functions: - - **User Operation Validation** functions handle calls to `validateUserOp` and check the validity of an ERC-4337 user operation. - - **Runtime Validation** functions run before an execution function when not called via a user operation, and enforce checks. Common checks include allowing execution only by an owner. -- An **execution function** is a smart contract function that defines the main execution step of a function for a modular account. -- The **standard execute** functions are two specific execute functions that are implemented natively by the modular account, and not on a module. These allow for open-ended execution. -- A **hook** is a smart contract function executed before or after another function, with the ability to modify state or cause the entire call to revert. There are four types of hooks: - - **Pre User Operation Validation Hook** functions run before user operation validation functions. These can enforce permissions on what actions a validation function may perform via user operations. - - **Pre Runtime Validation Hook** functions run before runtime validation functions. These can enforce permissions on what actions a validation function may perform via direct calls. - - **Pre Execution Hook** functions run before an execution function. They may optionally return data to be consumed by their related post execution hook functions. - - **Post Execution Hook** functions run after an execution function. They may optionally take returned data from their related pre execution hook functions. -- An **associated function** refers to either a validation function or a hook. -- A **native function** refers to a function implemented natively 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: execution functions, validation functions, or hooks. -- A module **manifest** is responsible for describing the execution functions, validation functions, and hooks that will be configured on the MSCA during installation, as well as the module’s metadata, dependency requirements, and permissions. +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 run can run before and/or after an execution function. The pre execution hook may optionally return data to be consumed by a post execution hook functions. +- 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. ### Overview @@ -82,16 +67,16 @@ Each step is modular, supporting different implementations, that allows for open - `IAccount.sol` from [ERC-4337](./eip-4337.md). - `IAccountExecute.sol` from [ERC-4337](./eip-4337.md). -- `IModuleManager.sol` to support installing and uninstalling modules. -- `IStandardExecutor.sol` to support open-ended execution. **Calls to modules through this SHOULD revert.** +- `IModularAccount.sol` to support module management and usage, and account identification. **Modular Smart Contract Accounts** **MAY** implement - `IAccountLoupe.sol` to support visibility in account states on-chain. +- [ERC-165](./eip-165.md) for interfaces installed from modules. **Modules** **MUST** implement -- `IModule.sol` described below and implement [ERC-165](./eip-165.md) for `IModule`. +- `IModule.sol` described below and implement ERC-165 for `IModule`. **Modules** **May** implement one of the following module types @@ -100,23 +85,56 @@ Each step is modular, supporting different implementations, that allows for open - `IExecutionModule` to support execution functions and their installations on account. - `IExecutionHookModule` to support pre & post execution hooks for execution functions. -#### `IModuleManager.sol` +#### `IModularAccount.sol` -Module manager interface. Modular Smart Contract Accounts **MUST** implement this interface to support installing and uninstalling modules. +Module execution and management interface. Modular Smart Contract Accounts **MUST** implement this interface to support installing and uninstalling modules, and open-ended execution. ```solidity + type ModuleEntity is bytes24; type ValidationConfig is bytes26; type HookConfig is bytes26; -interface IModuleManager { +struct Call { + // The target address for the account to call. + address target; + // The value to send with the call. + uint256 value; + // The calldata for the call. + bytes data; +} + +interface IModularAccount { event ExecutionInstalled(address indexed module, ExecutionManifest manifest); event ExecutionUninstalled(address indexed module, bool onUninstallSucceeded, ExecutionManifest manifest); event ValidationInstalled(address indexed module, uint32 indexed entityId); event ValidationUninstalled(address indexed module, uint32 indexed entityId, bool onUninstallSucceeded); + /// @notice Standard execute method. + /// @param target The target address for the account to call. + /// @param value The value to send with the call. + /// @param data The calldata for the call. + /// @return The return data from the call. + function execute(address target, uint256 value, bytes calldata data) external payable returns (bytes memory); + + /// @notice Standard executeBatch method. + /// @dev If the target is a module, the call SHOULD revert. If any of the calls revert, the entire batch MUST + /// revert. + /// @param calls The array of calls. + /// @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. + /// @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. + function executeWithAuthorization(bytes calldata data, bytes calldata authorization) + external + payable + returns (bytes memory); + /// @notice Install a module to the modular account. /// @param module The module to install. /// @param manifest the manifest describing functions to install @@ -135,7 +153,7 @@ interface IModuleManager { /// @param selectors The selectors to install the validation function for. /// @param installData Optional data to be decoded and used by the module to setup initial module state. /// @param hooks Optional hooks to install, associated with the validation function. These may be - /// pre-validation hooks or execution hooks. The expected format is a bytes26 HookConfig, followed by the + /// pre validation hooks or execution hooks. The expected format is a bytes26 HookConfig, followed by the /// install data, if any. function installValidation( ValidationConfig validationConfig, @@ -149,8 +167,8 @@ interface IModuleManager { /// @param uninstallData Optional data to be decoded and used by the module to clear module data for the /// account. /// @param hookUninstallData Optional data to be used by hooks for cleanup. If any are provided, the array must - /// be of a length equal to existing pre-validation hooks plus permission hooks. Hooks are indexed by - /// pre-validation hook order first, then permission hooks. + /// be of a length equal to existing pre validation hooks plus permission hooks. Hooks are indexed by + /// pre validation hook order first, then permission hooks. function uninstallValidation( ModuleEntity validationFunction, bytes calldata uninstallData, @@ -167,57 +185,19 @@ interface IModuleManager { ExecutionManifest calldata manifest, bytes calldata moduleUninstallData ) external; -} - -``` -#### `IStandardExecutor.sol` - -Standard execute interface. Modular Smart Contract Accounts **MUST** implement this interface to support open-ended execution. - -Standard execute functions SHOULD check whether the call's target implements the `IModule` interface via ERC-165. - -**If the target is a module, the call SHOULD revert.** This prevents accidental misconfiguration or misuse of modules (both installed and uninstalled). - -```solidity -struct Call { - // The target address for the account to call. - address target; - // The value to send with the call. - uint256 value; - // The calldata for the call. - bytes data; + /// @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. + /// @return The account ID. + function accountId() external view returns (string memory); } -interface IStandardExecutor { - /// @notice Standard execute method. - /// @param target The target address for the account to call. - /// @param value The value to send with the call. - /// @param data The calldata for the call. - /// @return The return data from the call. - function execute(address target, uint256 value, bytes calldata data) external payable returns (bytes memory); - - /// @notice Standard executeBatch method. - /// @dev If the target is a module, the call SHOULD revert. If any of the calls revert, the entire batch MUST - /// revert. - /// @param calls The array of calls. - /// @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. - /// @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. - function executeWithAuthorization(bytes calldata data, bytes calldata authorization) - external - payable - returns (bytes memory); -} ``` #### `IAccountLoupe.sol` -Module inspection interface. Modular Smart Contract Accounts **MAY** implement this interface to support visibility in module configuration on-chain. +Module inspection interface. Modular Smart Contract Accounts **MAY** implement this interface to support visibility in module configuration. ```solidity // Represents data associated with a specifc function selector. @@ -480,105 +460,10 @@ interface IExecutionHookModule is IModule { } ``` -### Module manifest - -The module manifest is responsible for describing the execution functions, validation functions, and hooks that will be configured on the MSCA during installation, as well as the module's metadata, dependencies, and permissions. - -```solidity -enum ManifestAssociatedFunctionType { - // Function is not defined. - NONE, - // Function belongs to this module. - SELF, - // Function belongs to an external module provided as a dependency during module installation. Modules MAY depend - // on external validation functions. It MUST NOT depend on external hooks, or installation will fail. - DEPENDENCY, - // Resolves to a magic value to always bypass runtime validation for a given function. - // This is only assignable on runtime validation functions. If it were to be used on a user op validation function, - // it would risk burning gas from the account. When used as a hook in any hook location, it is equivalent to not - // setting a hook and is therefore disallowed. - RUNTIME_VALIDATION_ALWAYS_ALLOW, - // Resolves to a magic value to always fail in a hook for a given function. - // This is only assignable to pre execution hooks. It should not be used on validation functions themselves, because - // this is equivalent to leaving the validation functions unset. It should not be used in post-exec hooks, because - // if it is known to always revert, that should happen as early as possible to save gas. - PRE_HOOK_ALWAYS_DENY -} - -/// @dev For functions of type `ManifestAssociatedFunctionType.DEPENDENCY`, the MSCA MUST find the module address -/// of the function at `dependencies[dependencyIndex]` during the call to `installModule(config)`. -struct ManifestFunction { - ManifestAssociatedFunctionType functionType; - uint8 entityId; - uint256 dependencyIndex; -} - -struct ManifestAssociatedFunction { - bytes4 executionSelector; - ManifestFunction associatedFunction; -} - -struct ManifestExecutionHook { - // TODO(erc6900 spec): These fields can be packed into a single word - bytes4 executionSelector; - uint8 entityId; - bool isPreHook; - bool isPostHook; -} - -struct ManifestExternalCallPermission { - address externalAddress; - bool permitAnySelector; - bytes4[] selectors; -} - -struct SelectorPermission { - bytes4 functionSelector; - string permissionDescription; -} - -/// @dev A struct holding fields to describe the module in a purely view context. Intended for front end clients. -struct ModuleMetadata { - // A human-readable name of the module. - string name; - // The version of the module, following the semantic versioning scheme. - string version; - // The author field SHOULD be a username representing the identity of the user or organization - // that created this module. - string author; - // String descriptions of the relative sensitivity of specific functions. The selectors MUST be selectors for - // functions implemented by this module. - SelectorPermission[] permissionDescriptors; -} - -/// @dev A struct describing how the module should be installed on a modular account. -struct ModuleManifest { - // List of ERC-165 interface IDs to add to account to support introspection checks. This MUST NOT include - // IModule's interface ID. - bytes4[] interfaceIds; - // If this module depends on other modules' validation functions, the interface IDs of those modules MUST be - // provided here, with its position in the array matching the `dependencyIndex` members of `ManifestFunction` - // structs used in the manifest. - bytes4[] dependencyInterfaceIds; - // Execution functions defined in this module to be installed on the MSCA. - bytes4[] executionFunctions; - // Module execution functions already installed on the MSCA that this module will be able to call. - bytes4[] permittedExecutionSelectors; - // Boolean to indicate whether the module can call any external address. - bool permitAnyExternalAddress; - // Boolean to indicate whether the module needs access to spend native tokens of the account. If false, the - // module MUST still be able to spend up to the balance that it sends to the account in the same call. - bool canSpendNativeToken; - ManifestExternalCallPermission[] permittedExternalCalls; - ManifestAssociatedFunction[] validationFunctions; - ManifestAssociatedFunction[] preValidationHooks; - ManifestExecutionHook[] executionHooks; -} - -``` - ### Expected behavior +TODO for v0.8 + #### Validations and their installation /uninstallation An account can have more than one validation installed. @@ -687,13 +572,11 @@ The `executeFromModuleExternal` function MUST allow modules to call external add ERC-4337 compatible accounts must implement the `IAccount` interface, which consists of only one method that bundles validation with execution: `validateUserOp`. A primary design rationale for this proposal is to extend the possible functions for a smart contract account beyond this single method by unbundling these and other functions, while retaining the benefits of account abstraction. -The function routing pattern of ERC-2535 is the logical starting point for achieving this extension into multi-functional accounts. It also meets our other primary design rationale of generalizing execution calls across multiple implementing contracts. However, a strict diamond pattern is constrained by its inability to customize validation schemes for specific execution functions in the context of `validateUserOp`, and its requirement of `delegatecall`. - -This proposal includes several interfaces that build on ERC-4337 and are inspired by ERC-2535. First, we standardize a set of modular functions that allow smart contract developers greater flexibility in bundling validation, execution, and hook logic. We also propose interfaces that take inspiration from the diamond standard and provide methods for querying execution functions, validation functions, and hooks on a modular account. The rest of the interfaces describe a module's methods for exposing its modular functions and desired configuration, and the modular account's methods for installing and removing modules and allowing execution across modules and external addresses. +This proposal includes several interfaces that build on ERC-4337. First, we standardize a set of modular functions that allow smart contract developers greater flexibility in bundling validation, execution, and hook logic. We also propose interfaces that provide methods for querying execution functions, validation functions, and hooks on a modular account. The rest of the interfaces describe a module's methods for exposing its modular functions and desired configuration, and the modular account's methods for installing and removing modules and allowing execution across modules and external addresses. ## Backwards Compatibility -No backward compatibility issues found. +TODO ## Reference Implementation @@ -701,13 +584,11 @@ See `https://github.com/erc6900/reference-implementation` ## Security Considerations -The modular smart contract accounts themselves are trusted components. Installed plugins are trusted to varying degrees, as plugins can interact with an arbitrarily large or small set of resources on an account. For example, a wide-reaching malicious plugin could add reverting hooks to native function selectors, bricking the account, or add execution functions that may drain the funds of the account. However, it is also possible to install a plugin with a very narrow domain, and depend on the correctness of the account behavior to enforce its limited access. Users should therefore be careful in what plugins to add to their account. - -Users should perform careful due diligence before installing a plugin and should be mindful of the fact that plugins are potentially dangerous. The plugin's manifest can give users an understanding of the domain of the plugin, i.e., the requested permissions to install certain validation functions and/or hooks on certain execution selectors. Generally, plugins that include native function selectors in their domain, e.g., plugins that add a validation hook to the native `uninstallPlugin()` function, can introduce significantly more harm than plugins that simply add validation hooks to function selectors that the plugin itself is adding to the account. +The modular smart contract accounts themselves are trusted components. Installed modules are trusted to varying degrees, as modules can interact with an arbitrarily large or small set of resources on an account. For example, a wide-reaching malicious module could add reverting hooks to native function selectors, bricking the account, or add execution functions that may drain the funds of the account. However, it is also possible to install a module with a very narrow domain, and depend on the correctness of the account behavior to enforce its limited access. Users should therefore be careful in what modules to add to their account. -Plugins can also add validation hooks to function selectors installed by other plugins. While usually, such a plugin would, e.g., add additional pre-validation hooks, it can also cause the previously installed plugin to be executed in an unintended context. For example, if a plugin were to only be intended to operate in the user operation context, its plugin manifest might only define user operation validation functions. However, another plugin might add a passing runtime validation function to that function selector, causing, for example, a session key plugin to suddenly be executed in a runtime validation context, circumventing all the parameter-validation that would have happened during user operation validation and granting unrestricted access to all session keys. Therefore, it is strongly recommended to always add reverting validation hooks to the context the plugin is not intended to be executed in. This recommendation may change in the next iteration of the standard. +Users should perform careful due diligence before installing a module and should be mindful of the fact that modules are potentially dangerous. The module's manifest can give users an understanding of the potential risks they are exposed to for that particular module. For instance, a request to install certain validation functions and/or hooks on certain execution selectors could potentially be a vector for DOS. -It is worth mentioning that execution hooks have no awareness of other execution hooks being performed in the same function selector execution setting. Since execution hooks can perform state changes, this reveals an important security consideration: An execution hook can only assure that at the time of its own execution, certain conditions are met, but this can not be generalized to the entire pre-execution context of potentially multiple pre-execution hooks. For example, a pre-execution hook cannot be assured that the storage it performed validation upon does not get further updated in subsequent pre-execution hooks. Even an associated post-execution hook potentially repeating the validation cannot assure that the storage remains unmodified because a prior post-execution hook may have reset the state. As long as the requirements checked by a plugin as part of an execution hook are only modifiable by the plugin itself, this can be considered safe. +Execution hooks have no awareness of other execution hooks being performed in the same function selector execution setting. Since execution hooks can perform state changes, this reveals an important security consideration: An execution hook can only assure that at the time of its own execution, certain conditions are met, but this can not be generalized to the entire pre execution context of potentially multiple pre execution hooks. For example, a pre execution hook cannot be assured that the storage it performed validation upon does not get further updated in subsequent pre execution hooks. Even a post execution hook potentially repeating the validation cannot assure that the storage remains unmodified because a prior post execution hook may have reset the state. As long as the requirements checked by a module as part of an execution hook are only modifiable by the module itself, this can be considered safe. ## Copyright diff --git a/test/utils/AccountTestBase.sol b/test/utils/AccountTestBase.sol index 5ce4324a..f4e37462 100644 --- a/test/utils/AccountTestBase.sol +++ b/test/utils/AccountTestBase.sol @@ -229,7 +229,7 @@ abstract contract AccountTestBase is OptimizedTest { return sig; } - // overload for the case where there are no pre-validation hooks + // overload for the case where there are no pre validation hooks function _encodeSignature(ModuleEntity validationFunction, uint8 globalOrNot, bytes memory validationData) internal pure @@ -239,7 +239,7 @@ abstract contract AccountTestBase is OptimizedTest { return _encodeSignature(validationFunction, globalOrNot, emptyPreValidationHookData, validationData); } - // overload for the case where there are no pre-validation hooks + // overload for the case where there are no pre validation hooks function _encode1271Signature(ModuleEntity validationFunction, bytes memory validationData) internal pure @@ -249,7 +249,7 @@ abstract contract AccountTestBase is OptimizedTest { return _encode1271Signature(validationFunction, emptyPreValidationHookData, validationData); } - // helper function to pack pre-validation hook datas, according to the sparse calldata segment spec. + // helper function to pack pre validation hook datas, according to the sparse calldata segment spec. function _packPreHookDatas(PreValidationHookData[] memory preValidationHookData) internal pure