Modules - bcnmy/nexus GitHub Wiki

Nexus is following the ERC-7579 specification. ERC-7579 is the standard for minimal modular smart accounts. Thus, modules are a crucial component that allows to add features and extend the functionality of Nexus.

There are currently 4 module types specified in ERC-7579 and all of them are supported by Nexus:

  • Validators: validate userOperations as per ERC-4337.
  • Executors: can initiate executions on behalf of the Smart Account they are installed on.
  • Fallback handlers: extend the native functionality of the Smart Account. Calls to functions which are not implemented in the Smart Account are forwarded to fallback handlers.
  • Hooks: hook executions by executing code before and after execution.

Installation

Install module

Nexus implements ERC-7579 installModule interface for the installation of the modules. It allows specifying which module to install and accepts data to perform the initial configuration for a module being installed. Another important parameter that has to be provided at module installation is the moduleTypeId.

Module Type Id

It is an incremental identifier used by accounts, modules, and other entities to identify the module type:

  • Validator modules have type id: 1
  • Executors have type id: 2
  • Fallback Handlers have type id: 3
  • Hooks have type id: 4

There is also Module type id: 0, which allows multi-type installations. This feature, compatible with ERC-7739, enables installing a module as multiple types (e.g., validator and executor) in one operation using the installModule interface.

Every module self-reports its type via the isModuleType(uint256 moduleTypeId) method, and a single module can implement multiple types at once.

Module Enable Mode

In some cases, a user may want to use a module that is not yet installed. To avoid the need for separate userOperation transactions to install the module, Nexus offers Enable Mode.

For example, if you need to use an executor module, you can batch the installModule(executor) call before the operation that uses this executor. However, for validators, since validation occurs before execution in ERC-4337, the validator must be installed and enabled before validation starts.

Enable Mode, which is compatible with ERC-7739, allows a module to be installed during the validation phase, and this is fully supported by Nexus and Entrypoint v0.7. Users sign an Enable Mode Data object that specifies which module to install and how it should be configured during the validation.

Any module type can be installed via Module Enable Mode, however, we believe it makes the most sense for validators and hooks.

Installation via Enable Mode with ERC-7739 Signature Validation

To install a module via Enable Mode, a user with appropriate rights (owner, etc.) must sign the Enable Mode Data Hash.
This hash is generated using EIP-712 to ensure phishing resistance and security through the following process:

_hashTypedData(
    keccak256(
        abi.encode(
            MODULE_ENABLE_MODE_TYPE_HASH,
            module,
            moduleType,
            userOpHash,
            keccak256(initData)
        )
    )
)

This process leverages ERC-7739, which introduces Typed Data Signatures to minimize signature replay attacks across multiple smart accounts. The structure ensures that the signature is tied to a specific module and moduleType to prevent unintended installations.

The key components of the EIP-712 hash are:

  • module: The module's address to be installed.
  • moduleType: Prevents the signature from being exploited to install the module under a different type.
  • userOpHash: Introduces uniqueness based on fields from the UserOperation (e.g., nonce).
  • keccak256(initData): Data used to initialize the module during the installation.

The data (ModuleType moduleType, bytes moduleInitData, bytes enableModeSignature, bytes userOpSignature), required to activate Enable Mode, is embedded in the userOp.signature field.
The encoding must follow a precise structure:

  • First 20 bytes: The module's address to be installed.
  • Next 32 bytes: ModuleType as uint256.
  • Next 4 bytes: Length of moduleInitData.
  • Next <length-of-moduleInitData> bytes: moduleInitData.
  • Next 4 bytes: Length of enableModeSignature.
  • Next <length-of-enableModeSignature> bytes: enableModeSignature.
  • Remaining bytes: userOpSignature.

In Solidity, the encoding is handled as follows:

bytes memory extendedUserOpSignature = abi.encodePacked(
    module,
    uint256(moduleType),
    bytes4(uint32(moduleInitData.length)),
    moduleInitData,
    bytes4(uint32(enableModeSignature.length)),
    enableModeSignature,
    userOpSignature
);

To decode this packed data, the parseEnableModeData method is used, enabling the system to extract and verify the signature.

Enhanced Security with ERC-7739

The ERC-7739 standard plays a crucial role in securing Enable Mode by validating signatures using nested EIP-712 flows. This prevents signature reuse across multiple accounts and ensures compatibility with wallet clients (e.g., MetaMask). If validation using TypedDataSign fails, the system gracefully falls back to PersonalSign workflows, ensuring robust protection against phishing and replay attacks.

Usage of Modules

Modules are used according to their types.

Usage of validators

Validators validate userOperations. The validator's address should be encoded into the userOp.nonce field. Nexus decodes this address and forwards the validation flow to the appropriate validator.

Usage of executors

Executors can be called directly or via Nexus.execute. The most important ability of executors is to perform actions on behalf of Nexus they are installed on by calling ERC-7579 executeFromExecutor method. For example, Executors can implement some complex logic of conditionally batching actions together.

Usage of fallback handlers

Sometimes, developers may want to add native functions to Nexus. To avoid dealing with upgrades, a Fallback can be installed on Nexus, and Nexus will forward the calls to non-existent methods to such modules that implement them.

Usage of hooks

Hooks are used to actually 'hook' executions. For example, they can store (ideally, temporarily) some data that reflects the state before the execution, and then compare it to what the state is after the execution. Hooks are the most convenient way to implement spending limits for Nexus for example.

Querying installed modules

There are two methods of querying this. One can check if a given module is installed as a given type on a given Nexus, by calling Nexus.isModuleInstalled method. If one just needs to learn what modules are installed, there are dedicated methods for it:

  • getValidatorsPaginated for validators
  • getExecutorsPaginated for executors
  • getActiveHook for the hook. As you may see, only one hook can be enabled at a given time (this can be a hook multiplexer though).
  • getFallbackHandlerBySelector to check where the implementation for a method with a given selector lives

Uninstalling the module

When uninstalling the module it is very important to provide the appropriate data that will deinitialize the module (by clearing its state or in any other way). Leaving the module initialized (configured for a given Smart Account) after its uninstallation may lead to unexpected behaviors when the module is installed on the same Smart Account next time.

The emergencyUninstallHook function is a safety mechanism designed to remove a potentially problematic hook module from the smart account in case of emergencies. It implements a timelock process to prevent immediate uninstallation, giving account owners a chance to intervene if the request is unauthorized. When called, it first initiates a one-day waiting period. If called again after this period but within three days, it uninstalls the hook. If not completed within three days, the process resets. This function balances the need for quick response to emergencies with safeguards against unauthorized removals. It's particularly useful when a hook module might be compromised or causing issues, allowing for its removal even if normal uninstallation methods are unavailable. The function can only be called by the EntryPoint, adding an extra layer of security. It also checks that the hook is actually installed before proceeding with any actions. This emergency uninstall feature provides a crucial failsafe for maintaining the security and functionality of the smart account in extreme situations. Resource locking ensures that key modules, such as hooks, cannot be uninstalled without waiting for a pre-defined timelock, safeguarding the account's integrity. Hooks are essential for adding custom behavior, including additional validations, logging, or triggering events based on the transaction flow.

The function emergencyUninstallHook is important for resource locking. Resource locking ensures that key modules, such as hooks, cannot be uninstalled without waiting for a pre-defined timelock, safeguarding the account's integrity. Hooks are essential for adding custom behavior, including additional validations, logging, or triggering events based on the transaction flow.