Skip to main content

Hook Multiplexer Module

Overview

The Hook Multiplexer module is a crucial component of our smart contract wallet system, enabling flexible and extensible hook management. This module allows the integration of multiple hooks for various transaction scenarios, enhancing the wallet's functionality and security.

Key Features

  • Support for multiple hook types (Global, Value, DelegateCall, Signature, Target-Signature)
  • Dynamic hook registration and removal
  • Pre-check and post-check execution for hooks
  • Limit on the number of hooks per type for gas efficiency
  • Reentrancy protection

Contract Structure

The HookMultiplexer contract implements the IHook interface and includes the following main components:

Enums

enum HookType {
GLOBAL,
VALUE,
DELEGATECALL,
SIG,
TARGET_SIG
}

HookType Enum Explanation

The HookType enum represents different categories of hooks that can be registered in the HookMultiplexer. Each type serves a specific purpose:

  1. GLOBAL:

    • Purpose: Hooks that are executed for every transaction.
    • Usage: Ideal for general checks or actions that should occur on all transactions, such as logging or global security checks.
  2. VALUE:

    • Purpose: Hooks that are executed only when a transaction involves sending Ether (i.e., when msg.value > 0).
    • Usage: Useful for implementing checks or actions specific to value transfer transactions, like spending limits or additional confirmations for high-value transfers.
  3. DELEGATECALL:

    • Purpose: Hooks that are executed when a transaction uses the delegatecall function.
    • Usage: Allows for specific checks or actions when the wallet is executing code in the context of another contract, which can be a powerful but potentially risky operation.
  4. SIG:

    • Purpose: Hooks that are executed based on the function signature (selector) of the transaction.
    • Usage: Enables attaching specific hooks to particular function calls, allowing for fine-grained control over different types of transactions.
  5. TARGET_SIG:

    • Purpose: Hooks that are executed based on both the target address and the function signature of the transaction.
    • Usage: Provides the most specific control, allowing hooks to be executed only for particular functions on particular target contracts.

This enum allows the HookMultiplexer to categorize and manage different types of hooks efficiently, providing a flexible system for implementing various security and functionality features in the wallet.

Structs

struct SignatureHooks {
bytes4[] allSigs;
mapping(bytes4 => address[]) sigHooks;
}

struct Config {
bool initialized;
mapping(HookType => address[]) hooks;
mapping(HookType => SignatureHooks) sigHooks;
mapping(address => mapping(HookType => bool)) isHookInstalled;
}

SignatureHooks Struct Explanation

The SignatureHooks struct is designed to efficiently manage hooks that are triggered by specific function signatures:

  1. allSigs (bytes4[]):

    • Purpose: Stores an array of all function signatures (selectors) that have hooks attached.
    • Usage: Allows for efficient iteration over all registered signatures without needing to know them in advance.
  2. sigHooks (mapping(bytes4 => address[])):

    • Purpose: Maps each function signature to an array of hook addresses.
    • Usage: Enables quick lookup of all hooks that should be executed for a specific function signature.

This structure allows for efficient management and execution of signature-specific hooks, supporting both the SIG and TARGET_SIG hook types.

Config Struct Explanation

The Config struct holds the entire configuration for an account's hooks:

  1. initialized (bool):

    • Purpose: Indicates whether the account has been initialized in the HookMultiplexer.
    • Usage: Prevents re-initialization and ensures proper setup before use.
  2. hooks (mapping(HookType => address[])):

    • Purpose: Stores arrays of hook addresses for each HookType.
    • Usage: Allows quick access to all hooks of a specific type (GLOBAL, VALUE, DELEGATECALL) for an account.
  3. sigHooks (mapping(HookType => SignatureHooks)):

    • Purpose: Stores signature-specific hooks for SIG and TARGET_SIG types.
    • Usage: Enables efficient lookup of hooks based on function signatures and/or target addresses.
  4. isHookInstalled (mapping(address => mapping(HookType => bool))):

    • Purpose: Tracks whether a specific hook is installed for a given HookType.
    • Usage: Provides a quick way to check if a hook is active without iterating through arrays, useful for preventing duplicate installations and optimizing removal operations.

This comprehensive structure allows the HookMultiplexer to manage a complex set of hooks efficiently, catering to various transaction scenarios while maintaining good performance.

State Variables

  • HOOK_LIMIT: Constant defining the maximum number of hooks per type (set to 10).
  • accountConfigs: Mapping of account addresses to their respective Config structs.

Main Functions

onInstall

Initializes the module for an account.

function onInstall(bytes calldata data) external override

onUninstall

Removes all configurations for an account.

function onUninstall(bytes calldata) external override

addHook

Adds a new hook of a specific type for an account.

function addHook(address hook, HookType hookType) external

addSigHook

Adds a signature-specific hook for an account.

function addSigHook(address hook, bytes4 sig, HookType hookType) external

removeHook

Removes a hook of a specific type for an account.

function removeHook(address hook, HookType hookType) external

removeSigHook

Removes a signature-specific hook for an account.

function removeSigHook(address hook, bytes4 sig, HookType hookType) external

preCheck

Executes pre-checks for all applicable hooks before a transaction.

function preCheck(
address msgSender,
uint256 msgValue,
bytes calldata msgData
) external override nonReentrant returns (bytes memory hookData)

postCheck

Executes post-checks for all hooks that were run in the pre-check phase.

function postCheck(bytes calldata hookData) external override nonReentrant

Usage

To use the Hook Multiplexer module:

  1. Install the module in your smart contract wallet.
  2. Add desired hooks using addHook or addSigHook.
  3. The wallet's execution function should call preCheck before executing a transaction and postCheck after the transaction.
  4. Remove hooks when no longer needed using removeHook or removeSigHook.

Security Considerations

  • The module uses a reentrancy guard to prevent reentrant calls in preCheck and postCheck.
  • There's a limit (HOOK_LIMIT) on the number of hooks that can be added per type to prevent gas limit issues.
  • Only initialized accounts can add or remove hooks.

Integration

To integrate this module with your smart contract wallet:

  1. Deploy the HookMultiplexer contract.
  2. Add the module to your wallet using the wallet's module management function.
  3. Ensure your wallet's execution function calls the preCheck and postCheck methods at appropriate times.

Conclusion

The Hook Multiplexer module provides a flexible and powerful way to extend the functionality of smart contract wallets. By allowing multiple hooks to be registered and executed based on various conditions, it enables advanced features like transaction filtering, additional security checks, and complex logic execution around wallet operations. The carefully designed enum and struct system allows for efficient management of different hook types, catering to a wide range of use cases while maintaining performance and gas efficiency.