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:
-
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.
-
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.
- Purpose: Hooks that are executed only when a transaction involves sending Ether (i.e., when
-
DELEGATECALL:- Purpose: Hooks that are executed when a transaction uses the
delegatecallfunction. - 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.
- Purpose: Hooks that are executed when a transaction uses the
-
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.
-
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:
-
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.
-
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:
-
initialized(bool):- Purpose: Indicates whether the account has been initialized in the HookMultiplexer.
- Usage: Prevents re-initialization and ensures proper setup before use.
-
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.
-
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.
-
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 respectiveConfigstructs.
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:
- Install the module in your smart contract wallet.
- Add desired hooks using
addHookoraddSigHook. - The wallet's execution function should call
preCheckbefore executing a transaction andpostCheckafter the transaction. - Remove hooks when no longer needed using
removeHookorremoveSigHook.
Security Considerations
- The module uses a reentrancy guard to prevent reentrant calls in
preCheckandpostCheck. - 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:
- Deploy the
HookMultiplexercontract. - Add the module to your wallet using the wallet's module management function.
- Ensure your wallet's execution function calls the
preCheckandpostCheckmethods 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.