Fallback Modules
Fallback modules extend OnChain Lab functionality by handling function calls that are not natively defined on the account contract, dispatched through the Solidity fallback function via selector-based
Fallback Modules
Fallback modules extend the native functionality of an OnChain Lab by handling calls to function selectors that are not defined on the account contract itself. When a transaction targets a selector that the Lab does not recognize, the Solidity fallback() function intercepts it and routes the call to a registered external module based on a per-selector configuration managed by the SelectorManager.
This mechanism allows Labs to support new interfaces, respond to new protocol interactions, and integrate with external systems β all without modifying the core account logic.
How It Works
Every OnChain Lab inherits from SelectorManager, which maintains a mapping from 4-byte function selectors to a SelectorConfig struct:
solidity
struct SelectorConfig {
IHook hook; // Hook address (or sentinel value)
address module; // Fallback module contract address
CallType callType; // Execution mode: CALLTYPE_SINGLE or CALLTYPE_DELEGATECALL
}When an external call arrives at the Lab with a selector that does not match any native function, the fallback() handler executes the following sequence:
State increment β The Lab increments an internal state counter to track executions and support anti-fraud mechanisms.
Selector lookup β The handler reads the
SelectorConfigformsg.sigfrom the selector storage slot.Installation check β If the hook field equals
HOOK_MODULE_NOT_INSTALLED(address zero), the selector has no registered module and the call reverts withInvalidSelector().Access control β If the hook field equals
HOOK_ONLY_ENTRYPOINT, only the ERC-4337 EntryPoint contract may invoke the selector. Direct calls from any other address revert withInvalidCaller().Registry verification β The module address is checked against the ERC-7484 Module Registry to confirm it is an attested, approved fallback module (
MODULE_TYPE_FALLBACK).Dispatch β The call is forwarded to the module using one of two execution modes depending on the configured
CallType.
Call Types
Fallback modules support two execution modes, each suited to different use cases:
CALLTYPE_SINGLE (0x00) β The call is forwarded to the module contract as a standard external call using the ERC-2771 trusted forwarder pattern. The Lab appends the original msg.sender address to the calldata before calling the module, allowing the module to identify the true caller even though the call is proxied through the Lab. This is the recommended mode for modules that maintain their own storage.
CALLTYPE_DELEGATECALL (0xFF) β The call is executed via delegatecall, meaning the module's code runs in the context of the Lab's storage. This enables modules to directly read and modify Lab state, but must be used with extreme care to avoid storage slot collisions. Delegatecall modules skip the onInstall lifecycle callback since they operate within the Lab's own storage context.
Installation
Fallback modules are installed through the installModule function on the Lab account, callable only via the EntryPoint (ensuring the operation has been validated). The installation requires:
Module type β
MODULE_TYPE_FALLBACK(type ID3)Module address β The address of the fallback module contract
Initialization data β At least 24 bytes encoding the function selector (4 bytes), the hook address (20 bytes), and the selector-specific configuration data (which includes the
CallTypebyte followed by any module-specific init parameters)
During installation, the system performs a registry check via ERC-7484 to verify the module is attested for the fallback type. The SelectorManager then stores the configuration and emits a ModuleInstalled event. If no hook is explicitly provided (hook address is zero), the system defaults to HOOK_ONLY_ENTRYPOINT, restricting invocation to validated UserOperations only.
Hook Integration
Each fallback selector can optionally be associated with a hook module that executes before the fallback call is dispatched. Hooks provide an additional control layer for enforcing constraints such as spending limits, access policies, or audit logging on a per-selector basis.
Hook support in the current implementation uses sentinel values to indicate the hook state for each selector:
address(0)
HOOK_MODULE_NOT_INSTALLED
No module registered for this selector
address(1)
HOOK_MODULE_INSTALLED
Hook module is installed and active
address(0xFFfF...FfFf)
HOOK_ONLY_ENTRYPOINT
No hook; only EntryPoint may call
Note: Hook execution logic is currently defined in the architecture but not yet active. The
HookManageris a stub awaiting full implementation. When hooks are fully supported, they will run pre-execution checks before fallback dispatch.
Use Cases
Fallback modules enable OnChain Labs to support capabilities that are not part of the core account contract. Example use cases include:
Token receiving β Implementing
onERC721Received,onERC1155Received, or similar callback interfaces so the Lab can receive NFTs and multi-token transfersFlash loan participation β Implementing flash loan callback interfaces to allow Labs to act as flash loan receivers
Protocol integrations β Supporting interaction interfaces required by external DeFi protocols, governance systems, or marketplace contracts
Custom query interfaces β Exposing read-only view functions that aggregate or compute data from the Lab's state for external consumers
Security Considerations
Fallback modules are security-critical because they can execute arbitrary logic in response to any unrecognized function call on the Lab. Several safeguards are built into the architecture:
The ERC-7484 Module Registry provides attestation-based trust. Every fallback module must be attested as type MODULE_TYPE_FALLBACK before it can be dispatched, ensuring only reviewed and approved modules can handle calls.
The default hook sentinel (HOOK_ONLY_ENTRYPOINT) ensures that when no explicit hook is configured, fallback selectors can only be invoked through the EntryPoint β meaning every call must pass UserOperation validation first. This prevents unauthorized contracts or EOAs from directly triggering fallback logic.
Delegatecall modules operate in the Lab's storage context and require particular caution. A malicious or buggy delegatecall module could corrupt Lab state, modify ownership, or drain funds. Only thoroughly audited modules should be installed with CALLTYPE_DELEGATECALL.
The state counter increment on every fallback invocation provides an additional anti-replay and execution tracking mechanism.
Contract Reference
SelectorManager.sol
Manages per-selector fallback configuration and storage
src/core/SelectorManager.sol
Modular_OnChainLab.sol
Contains the fallback() handler and installModule logic
src/Modular_OnChainLab.sol
ExecLib.sol
Provides doFallback2771Call and executeDelegatecall helpers
src/utils/ExecLib.sol
HookManager.sol
Hook lifecycle management (stub β not yet active)
src/core/HookManager.sol
Constants.sol
Defines module types, call types, sentinel values, and storage slots
src/types/Constants.sol
Last updated