Skip to content

Commit

Permalink
feat: add (un)/installation expected behavior for both validation and…
Browse files Browse the repository at this point in the history
… execution
  • Loading branch information
fangting-alchemy committed Aug 29, 2024
1 parent 2725fbc commit 453cef2
Showing 1 changed file with 36 additions and 55 deletions.
91 changes: 36 additions & 55 deletions standard/ERCs/erc-6900.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ 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 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.
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.
Expand Down Expand Up @@ -471,72 +469,55 @@ 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.

#### Responsibilties of `StandardExecutor` and `ModuleExecutor`

`StandardExecutor` functions are used for open-ended calls to external addresses.

`ModuleExecutor` functions are specifically used by modules to request the account to execute with account's context. Explicit permissions are required for modules to use `ModuleExecutor`.

The following behavior MUST be followed:

- `StandardExecutor` can NOT call module execution functions and/or `ModuleExecutor`. This is guaranteed by checking whether the call's target implements the `IModule` interface via ERC-165 as required.
- `StandardExecutor` can NOT be called by module execution functions and/or `ModuleExecutor`.
- Module execution functions MUST NOT request access to `StandardExecutor`, they MAY request access to `ModuleExecutor`.

#### Calls to `installModule`

The function `installModule` accepts 3 parameters: the address of the module to install, the Keccak-256 hash of the module's manifest, ABI-encoded data to pass to the module's `onInstall` callback.

The function MUST retrieve the module's manifest by calling `moduleManifest()` using `staticcall`.

The function MUST perform the following preliminary checks:
During validation installation, the account MUST correctly set flags and other fields based on the incoming data provided by users.

- Revert if the module has already been installed on the modular account.
- Revert if the module does not implement ERC-165 or does not support the `IModule` interface.
- Revert if `manifestHash` does not match the computed Keccak-256 hash of the module's returned manifest. This prevents installation of modules that attempt to install a different module configuration than the one that was approved by the client.
- Revert if any address in `dependencies` does not support the interface at its matching index in the manifest's `dependencyInterfaceIds`, or if the two array lengths do not match, or if any of the dependencies are not already installed on the modular account.
- the account MUST install all pre validation hooks required by the user and call `onInstall` with the user-provided data on the hook module to initialize the states.
- the account MUST install all permission hooks required by the user and call `onInstall` with the user-provided data on the hook module to initialize the states.
- the account MUST add all selectors required by the user that the validation can validate.
- the account MUST set `isGlobal` and `isSignatureValidation` flags as required.
- the account MUST call `onInstall` on the validation module to initialize the states.
- the account MUST emit `ValidationInstalled` as defined in the interface for all installed validations.

The function MUST record the manifest hash and dependencies that were used for the module's installation. Each dependency's record MUST also be updated to reflect that it has a new dependent. These records MUST be used to ensure calls to `uninstallModule` are comprehensive and undo all edited configuration state from installation. The mechanism by which these records are stored and validated is up to the implementation.
During validation uninstallation, the account MUST correctly clear flags and other fields based on the incoming data provided by users.

The function MUST store the module's permitted function selectors, permitted external calls, and whether it can spend the account's native tokens, to be able to validate calls to `executeFromModule` and `executeFromModuleExternal`.
- the account MUST clear all flags for the validation function, including `isGlobal` and `isSignatureValidation`.
- the account MUST remomve all hooks and clear hook module states by calling `onUninstall` with the user-provided data for each hook, including both pre validation hooks and permission hooks.
- 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 function MUST parse through the execution functions, validation functions, and hooks in the manifest and add them to the modular account after resolving each `ManifestFunction` type.
#### Execution and their installation /uninstallation

- Each execution function selector MUST be added as a valid execution function on the modular account. If the function selector has already been added or matches the selector of a native function, the function SHOULD revert.
- If a validation function is to be added to a selector that already has that type of validation function, the function SHOULD revert.
An account can install any number of execution functions.
An execution function selector MUST be unique to the account.
An execution function selector MUST not conflict with native ERC-4337 and ERC-6900 functions.

The function MAY store the interface IDs provided in the manifest's `interfaceIds` and update its `supportsInterface` behavior accordingly.
During execution installation, the account MUST correctly set flags and other fields based on the incoming data and module manifest provided by users.

Next, the function MUST call the module's `onInstall` callback with the data provided in the `moduleInstallData` parameter. This serves to initialize the module state for the modular account. If `onInstall` reverts, the `installModule` function MUST revert.
- the account MUST install all execution functions and set flags and fields accordingly as specified in the manifest.
- the account MUST add all execution hooks as specified in the manifest.
- the account MUST add all supported interfaces as specified in the manifest.
- the account MUST call `onInstall` on the execution module to initialize the states.
- the account MUST emit `ExecutionInstalled` as defined in the interface for all installed executions.

Finally, the function MUST emit the event `ModuleInstalled` with the module's address, the hash of its manifest, and the dependencies that were used.
During execution uninstallation, the account MUST correctly clear flags and other fields based on the incoming data and module manifest provided by users.

> **⚠️ The ability to install and uninstall modules is very powerful. The security of these functions determines the security of the account. It is critical for modular account implementers to make sure the implementation of the functions in `IModuleManager` have the proper security consideration and access control in place.**
- the account MUST remove all execution functions and clear flags and fields accordingly 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 MUST call `onUnInstall` on the execution module to initialize the states and track call success.
- the account MUST emit `ExecutionUninstalled` as defined in the interface for all uninstalled executions.

#### Calls to `uninstallModule`

The function `uninstallModule` accepts 3 parameters: the address of the module to uninstall, a bytes field that may have custom requirements or uses by the implementing account, and ABI-encoded data to pass to the module's `onUninstall` callback.

The function MUST revert if the module is not installed on the modular account.

The function SHOULD perform the following checks:

- Revert if the hash of the manifest used at install time does not match the computed Keccak-256 hash of the module's current manifest. This prevents unclean removal of modules that attempt to force a removal of a different module configuration than the one that was originally approved by the client for installation. To allow for removal of such modules, the modular account MAY implement the capability for the manifest to be encoded in the config field as a parameter.
- Revert if there is at least 1 other installed module that depends on validation functions added by this module. Modules used as dependencies SHOULD NOT be uninstalled while dependent modules exist.

The function SHOULD update account storage to reflect the uninstall via inspection functions, such as those defined by `IModularAccountView`. Each dependency's record SHOULD also be updated to reflect that it has no longer has this module as a dependent.

The function MUST remove records for the module's manifest hash, dependencies, permitted function selectors, permitted external calls, and whether it can spend the account's native tokens.

The function MUST parse through the execution functions, validation functions, and hooks in the manifest and remove them from the modular account after resolving each `ManifestFunction` type. If multiple modules added the same hook, it MUST persist until the last module is uninstalled.
#### Responsibilties of `StandardExecutor` and `ModuleExecutor`

If the account stored the interface IDs provided in the manifest's `interfaceIds` during installation, it MUST remove them and update its `supportsInterface` behavior accordingly. If multiple modules added the same interface ID, it MUST persist until the last module is uninstalled.
`StandardExecutor` functions are used for open-ended calls to external addresses.

Next, the function MUST call the module's `onUninstall` callback with the data provided in the `moduleUninstallData` parameter. This serves to clear the module state for the modular account. If `onUninstall` reverts, execution SHOULD continue to allow the uninstall to complete.
`ModuleExecutor` functions are specifically used by modules to request the account to execute with account's context. Explicit permissions are required for modules to use `ModuleExecutor`.

Finally, the function MUST emit the event `ModuleUninstalled` with the module's address and whether the `onUninstall` callback succeeded.
The following behavior MUST be followed:

> **⚠️ Incorrectly uninstalled modules can prevent uninstalls of their dependencies. Therefore, some form of validation that the uninstall step completely and correctly removes the module and its usage of dependencies is required.**
- `StandardExecutor` can NOT call module execution functions and/or `ModuleExecutor`. This is guaranteed by checking whether the call's target implements the `IModule` interface via ERC-165 as required.
- `StandardExecutor` can NOT be called by module execution functions and/or `ModuleExecutor`.
- Module execution functions MUST NOT request access to `StandardExecutor`, they MAY request access to `ModuleExecutor`.

#### Calls to `validateUserOp`

Expand Down

0 comments on commit 453cef2

Please sign in to comment.