Contract

0x000000F5b753Fdd20C5CA2D7c1210b3Ab1EA5903

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
14545822024-12-24 11:13:013 days ago1735038781  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NexusBootstrap

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 999 runs

Other Settings:
cancun EvmVersion
File 1 of 21 : NexusBootstrap.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. For security issues, contact: [email protected]

import { ModuleManager } from "../base/ModuleManager.sol";
import { IModule } from "../interfaces/modules/IModule.sol";
import { IERC7484 } from "../interfaces/IERC7484.sol";

/// @title NexusBootstrap Configuration for Nexus
/// @notice Provides configuration and initialization for Nexus smart accounts.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
struct BootstrapConfig {
    address module;
    bytes data;
}

/// @title NexusBootstrap
/// @notice Manages the installation of modules into Nexus smart accounts using delegatecalls.
contract NexusBootstrap is ModuleManager {
    /// @notice Initializes the Nexus account with a single validator.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @param validator The address of the validator module.
    /// @param data The initialization data for the validator module.
    function initNexusWithSingleValidator(
        IModule validator,
        bytes calldata data,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external {
        _configureRegistry(registry, attesters, threshold);
        _installValidator(address(validator), data);
    }

    /// @notice Initializes the Nexus account with multiple modules.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @param validators The configuration array for validator modules.
    /// @param executors The configuration array for executor modules.
    /// @param hook The configuration for the hook module.
    /// @param fallbacks The configuration array for fallback handler modules.
    function initNexus(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external {
        _configureRegistry(registry, attesters, threshold);

        // Initialize validators
        for (uint256 i = 0; i < validators.length; i++) {
            _installValidator(validators[i].module, validators[i].data);
        }

        // Initialize executors
        for (uint256 i = 0; i < executors.length; i++) {
            if (executors[i].module == address(0)) continue;
            _installExecutor(executors[i].module, executors[i].data);
        }

        // Initialize hook
        if (hook.module != address(0)) {
            _installHook(hook.module, hook.data);
        }

        // Initialize fallback handlers
        for (uint256 i = 0; i < fallbacks.length; i++) {
            if (fallbacks[i].module == address(0)) continue;
            _installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
        }
    }

    /// @notice Initializes the Nexus account with a scoped set of modules.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @param validators The configuration array for validator modules.
    /// @param hook The configuration for the hook module.
    function initNexusScoped(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external {
        _configureRegistry(registry, attesters, threshold);

        // Initialize validators
        for (uint256 i = 0; i < validators.length; i++) {
            _installValidator(validators[i].module, validators[i].data);
        }

        // Initialize hook
        if (hook.module != address(0)) {
            _installHook(hook.module, hook.data);
        }
    }

    /// @notice Prepares calldata for the initNexus function.
    /// @param validators The configuration array for validator modules.
    /// @param executors The configuration array for executor modules.
    /// @param hook The configuration for the hook module.
    /// @param fallbacks The configuration array for fallback handler modules.
    /// @return init The prepared calldata for initNexus.
    function getInitNexusCalldata(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external view returns (bytes memory init) {
        init = abi.encode(address(this), abi.encodeCall(this.initNexus, (validators, executors, hook, fallbacks, registry, attesters, threshold)));
    }

    /// @notice Prepares calldata for the initNexusScoped function.
    /// @param validators The configuration array for validator modules.
    /// @param hook The configuration for the hook module.
    /// @return init The prepared calldata for initNexusScoped.
    function getInitNexusScopedCalldata(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external view returns (bytes memory init) {
        init = abi.encode(address(this), abi.encodeCall(this.initNexusScoped, (validators, hook, registry, attesters, threshold)));
    }

    /// @notice Prepares calldata for the initNexusWithSingleValidator function.
    /// @param validator The configuration for the validator module.
    /// @return init The prepared calldata for initNexusWithSingleValidator.
    function getInitNexusWithSingleValidatorCalldata(
        BootstrapConfig calldata validator,
        IERC7484 registry,
        address[] calldata attesters,
        uint8 threshold
    ) external view returns (bytes memory init) {
        init = abi.encode(
            address(this),
            abi.encodeCall(this.initNexusWithSingleValidator, (IModule(validator.module), validator.data, registry, attesters, threshold))
        );
    }

    /// @dev EIP712 domain name and version.
    function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) {
        name = "NexusBootstrap";
        version = "1.0.0";
    }
}

File 2 of 21 : ModuleManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { SentinelListLib } from "sentinellist/SentinelList.sol";
import { Storage } from "./Storage.sol";
import { IHook } from "../interfaces/modules/IHook.sol";
import { IModule } from "../interfaces/modules/IModule.sol";
import { IExecutor } from "../interfaces/modules/IExecutor.sol";
import { IFallback } from "../interfaces/modules/IFallback.sol";
import { IValidator } from "../interfaces/modules/IValidator.sol";
import { CallType, CALLTYPE_SINGLE, CALLTYPE_STATIC } from "../lib/ModeLib.sol";
import { ExecLib } from "../lib/ExecLib.sol";
import { LocalCallDataParserLib } from "../lib/local/LocalCallDataParserLib.sol";
import { IModuleManagerEventsAndErrors } from "../interfaces/base/IModuleManagerEventsAndErrors.sol";
import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK, MODULE_TYPE_HOOK, MODULE_TYPE_MULTI, MODULE_ENABLE_MODE_TYPE_HASH, ERC1271_MAGICVALUE } from "../types/Constants.sol";
import { EIP712 } from "solady/utils/EIP712.sol";
import { ExcessivelySafeCall } from "excessively-safe-call/ExcessivelySafeCall.sol";
import { RegistryAdapter } from "./RegistryAdapter.sol";

/// @title Nexus - ModuleManager
/// @notice Manages Validator, Executor, Hook, and Fallback modules within the Nexus suite, supporting
/// @dev Implements SentinelList for managing modules via a linked list structure, adhering to ERC-7579.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
abstract contract ModuleManager is Storage, EIP712, IModuleManagerEventsAndErrors, RegistryAdapter {
    using SentinelListLib for SentinelListLib.SentinelList;
    using LocalCallDataParserLib for bytes;
    using ExecLib for address;
    using ExcessivelySafeCall for address;

    /// @notice Ensures the message sender is a registered executor module.
    modifier onlyExecutorModule() virtual {
        require(_getAccountStorage().executors.contains(msg.sender), InvalidModule(msg.sender));
        _;
    }

    /// @notice Does pre-checks and post-checks using an installed hook on the account.
    /// @dev sender, msg.data and msg.value is passed to the hook to implement custom flows.
    modifier withHook() {
        address hook = _getHook();
        if (hook == address(0)) {
            _;
        } else {
            bytes memory hookData = IHook(hook).preCheck(msg.sender, msg.value, msg.data);
            _;
            IHook(hook).postCheck(hookData);
        }
    }

    receive() external payable {}

    /// @dev Fallback function to manage incoming calls using designated handlers based on the call type.
    fallback(bytes calldata callData) external payable withHook returns (bytes memory) {
        return _fallback(callData);
    }

    /// @dev Retrieves a paginated list of validator addresses from the linked list.
    /// This utility function is not defined by the ERC-7579 standard and is implemented to facilitate
    /// easier management and retrieval of large sets of validator modules.
    /// @param cursor The address to start pagination from, or zero to start from the first entry.
    /// @param size The number of validator addresses to return.
    /// @return array An array of validator addresses.
    /// @return next The address to use as a cursor for the next page of results.
    function getValidatorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next) {
        (array, next) = _paginate(_getAccountStorage().validators, cursor, size);
    }

    /// @dev Retrieves a paginated list of executor addresses from the linked list.
    /// This utility function is not defined by the ERC-7579 standard and is implemented to facilitate
    /// easier management and retrieval of large sets of executor modules.
    /// @param cursor The address to start pagination from, or zero to start from the first entry.
    /// @param size The number of executor addresses to return.
    /// @return array An array of executor addresses.
    /// @return next The address to use as a cursor for the next page of results.
    function getExecutorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next) {
        (array, next) = _paginate(_getAccountStorage().executors, cursor, size);
    }

    /// @notice Retrieves the currently active hook address.
    /// @return hook The address of the active hook module.
    function getActiveHook() external view returns (address hook) {
        return _getHook();
    }

    /// @notice Fetches the fallback handler for a specific selector.
    /// @param selector The function selector to query.
    /// @return calltype The type of call that the handler manages.
    /// @return handler The address of the fallback handler.
    function getFallbackHandlerBySelector(bytes4 selector) external view returns (CallType, address) {
        FallbackHandler memory handler = _getAccountStorage().fallbacks[selector];
        return (handler.calltype, handler.handler);
    }

    /// @dev Initializes the module manager by setting up default states for validators and executors.
    function _initModuleManager() internal virtual {
        // account module storage
        AccountStorage storage ams = _getAccountStorage();
        ams.executors.init();
        ams.validators.init();
    }

    /// @dev Implements Module Enable Mode flow.
    /// @param packedData Data source to parse data required to perform Module Enable mode from.
    /// @return userOpSignature the clean signature which can be further used for userOp validation
    function _enableMode(bytes32 userOpHash, bytes calldata packedData) internal returns (bytes calldata userOpSignature) {
        address module;
        uint256 moduleType;
        bytes calldata moduleInitData;
        bytes calldata enableModeSignature;

        (module, moduleType, moduleInitData, enableModeSignature, userOpSignature) = packedData.parseEnableModeData();

        if (!_checkEnableModeSignature(_getEnableModeDataHash(module, moduleType, userOpHash, moduleInitData), enableModeSignature))
            revert EnableModeSigError();

        _installModule(moduleType, module, moduleInitData);
    }

    /// @notice Installs a new module to the smart account.
    /// @param moduleTypeId The type identifier of the module being installed, which determines its role:
    /// - 0 for MultiType
    /// - 1 for Validator
    /// - 2 for Executor
    /// - 3 for Fallback
    /// - 4 for Hook
    /// @param module The address of the module to install.
    /// @param initData Initialization data for the module.
    /// @dev This function goes through hook checks via withHook modifier.
    /// @dev No need to check that the module is already installed, as this check is done
    /// when trying to sstore the module in an appropriate SentinelList
    function _installModule(uint256 moduleTypeId, address module, bytes calldata initData) internal withHook {
        if (module == address(0)) revert ModuleAddressCanNotBeZero();
        if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
            _installValidator(module, initData);
        } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
            _installExecutor(module, initData);
        } else if (moduleTypeId == MODULE_TYPE_FALLBACK) {
            _installFallbackHandler(module, initData);
        } else if (moduleTypeId == MODULE_TYPE_HOOK) {
            _installHook(module, initData);
        } else if (moduleTypeId == MODULE_TYPE_MULTI) {
            _multiTypeInstall(module, initData);
        } else {
            revert InvalidModuleTypeId(moduleTypeId);
        }
    }

    /// @dev Installs a new validator module after checking if it matches the required module type.
    /// @param validator The address of the validator module to be installed.
    /// @param data Initialization data to configure the validator upon installation.
    function _installValidator(address validator, bytes calldata data) internal virtual withRegistry(validator, MODULE_TYPE_VALIDATOR) {
        if (!IValidator(validator).isModuleType(MODULE_TYPE_VALIDATOR)) revert MismatchModuleTypeId(MODULE_TYPE_VALIDATOR);
        _getAccountStorage().validators.push(validator);
        IValidator(validator).onInstall(data);
    }

    /// @dev Uninstalls a validator module /!\ ensuring the account retains at least one validator.
    /// @param validator The address of the validator to be uninstalled.
    /// @param data De-initialization data to configure the validator upon uninstallation.
    function _uninstallValidator(address validator, bytes calldata data) internal virtual {
        SentinelListLib.SentinelList storage validators = _getAccountStorage().validators;

        (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes));

        // Perform the removal first
        validators.pop(prev, validator);

        // Sentinel pointing to itself / zero means the list is empty / uninitialized, so check this after removal
        // Below error is very specific to uninstalling validators.
        require(_hasValidators(), CanNotRemoveLastValidator());
        validator.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, disableModuleData));
    }

    /// @dev Installs a new executor module after checking if it matches the required module type.
    /// @param executor The address of the executor module to be installed.
    /// @param data Initialization data to configure the executor upon installation.
    function _installExecutor(address executor, bytes calldata data) internal virtual withRegistry(executor, MODULE_TYPE_EXECUTOR) {
        if (!IExecutor(executor).isModuleType(MODULE_TYPE_EXECUTOR)) revert MismatchModuleTypeId(MODULE_TYPE_EXECUTOR);
        _getAccountStorage().executors.push(executor);
        IExecutor(executor).onInstall(data);
    }

    /// @dev Uninstalls an executor module by removing it from the executors list.
    /// @param executor The address of the executor to be uninstalled.
    /// @param data De-initialization data to configure the executor upon uninstallation.
    function _uninstallExecutor(address executor, bytes calldata data) internal virtual {
        (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes));
        _getAccountStorage().executors.pop(prev, executor);
        executor.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, disableModuleData));
    }

    /// @dev Installs a hook module, ensuring no other hooks are installed before proceeding.
    /// @param hook The address of the hook to be installed.
    /// @param data Initialization data to configure the hook upon installation.
    function _installHook(address hook, bytes calldata data) internal virtual withRegistry(hook, MODULE_TYPE_HOOK) {
        if (!IHook(hook).isModuleType(MODULE_TYPE_HOOK)) revert MismatchModuleTypeId(MODULE_TYPE_HOOK);
        address currentHook = _getHook();
        require(currentHook == address(0), HookAlreadyInstalled(currentHook));
        _setHook(hook);
        IHook(hook).onInstall(data);
    }

    /// @dev Uninstalls a hook module, ensuring the current hook matches the one intended for uninstallation.
    /// @param hook The address of the hook to be uninstalled.
    /// @param data De-initialization data to configure the hook upon uninstallation.
    function _uninstallHook(address hook, bytes calldata data) internal virtual {
        _setHook(address(0));
        hook.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, data));
    }

    /// @dev Sets the current hook in the storage to the specified address.
    /// @param hook The new hook address.
    function _setHook(address hook) internal virtual {
        _getAccountStorage().hook = IHook(hook);
    }

    /// @dev Installs a fallback handler for a given selector with initialization data.
    /// @param handler The address of the fallback handler to install.
    /// @param params The initialization parameters including the selector and call type.
    function _installFallbackHandler(address handler, bytes calldata params) internal virtual withRegistry(handler, MODULE_TYPE_FALLBACK) {
        if (!IFallback(handler).isModuleType(MODULE_TYPE_FALLBACK)) revert MismatchModuleTypeId(MODULE_TYPE_FALLBACK);
        // Extract the function selector from the provided parameters.
        bytes4 selector = bytes4(params[0:4]);

        // Extract the call type from the provided parameters.
        CallType calltype = CallType.wrap(bytes1(params[4]));

        require(calltype == CALLTYPE_SINGLE || calltype == CALLTYPE_STATIC, FallbackCallTypeInvalid());

        // Extract the initialization data from the provided parameters.
        bytes memory initData = params[5:];

        // Revert if the selector is either `onInstall(bytes)` (0x6d61fe70) or `onUninstall(bytes)` (0x8a91b0e3) or explicit bytes(0).
        // These selectors are explicitly forbidden to prevent security vulnerabilities.
        // Allowing these selectors would enable unauthorized users to uninstall and reinstall critical modules.
        // If a validator module is uninstalled and reinstalled without proper authorization, it can compromise
        // the account's security and integrity. By restricting these selectors, we ensure that the fallback handler
        // cannot be manipulated to disrupt the expected behavior and security of the account.
        require(!(selector == bytes4(0x6d61fe70) || selector == bytes4(0x8a91b0e3) || selector == bytes4(0)), FallbackSelectorForbidden());

        // Revert if a fallback handler is already installed for the given selector.
        // This check ensures that we do not overwrite an existing fallback handler, which could lead to unexpected behavior.
        require(!_isFallbackHandlerInstalled(selector), FallbackAlreadyInstalledForSelector(selector));

        // Store the fallback handler and its call type in the account storage.
        // This maps the function selector to the specified fallback handler and call type.
        _getAccountStorage().fallbacks[selector] = FallbackHandler(handler, calltype);

        // Invoke the `onInstall` function of the fallback handler with the provided initialization data.
        // This step allows the fallback handler to perform any necessary setup or initialization.
        IFallback(handler).onInstall(initData);
    }

    /// @dev Uninstalls a fallback handler for a given selector.
    /// @param fallbackHandler The address of the fallback handler to uninstall.
    /// @param data The de-initialization data containing the selector.
    function _uninstallFallbackHandler(address fallbackHandler, bytes calldata data) internal virtual {
        _getAccountStorage().fallbacks[bytes4(data[0:4])] = FallbackHandler(address(0), CallType.wrap(0x00));
        fallbackHandler.excessivelySafeCall(gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, data[4:]));
    }

    /// @notice Installs a module with multiple types in a single operation.
    /// @dev This function handles installing a multi-type module by iterating through each type and initializing it.
    /// The initData should include an ABI-encoded tuple of (uint[] types, bytes[] initDatas).
    /// @param module The address of the multi-type module.
    /// @param initData Initialization data for each type within the module.
    function _multiTypeInstall(address module, bytes calldata initData) internal virtual {
        (uint256[] calldata types, bytes[] calldata initDatas) = initData.parseMultiTypeInitData();

        uint256 length = types.length;
        if (initDatas.length != length) revert InvalidInput();

        // iterate over all module types and install the module as a type accordingly
        for (uint256 i; i < length; i++) {
            uint256 theType = types[i];

            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                      INSTALL VALIDATORS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            if (theType == MODULE_TYPE_VALIDATOR) {
                _installValidator(module, initDatas[i]);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       INSTALL EXECUTORS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            else if (theType == MODULE_TYPE_EXECUTOR) {
                _installExecutor(module, initDatas[i]);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       INSTALL FALLBACK                     */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            else if (theType == MODULE_TYPE_FALLBACK) {
                _installFallbackHandler(module, initDatas[i]);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*          INSTALL HOOK (global only, not sig-specific)      */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            else if (theType == MODULE_TYPE_HOOK) {
                _installHook(module, initDatas[i]);
            }
        }
    }

    /// @notice Checks if an enable mode signature is valid.
    /// @param structHash data hash.
    /// @param sig Signature.
    function _checkEnableModeSignature(bytes32 structHash, bytes calldata sig) internal view returns (bool) {
        address enableModeSigValidator = address(bytes20(sig[0:20]));
        if (!_isValidatorInstalled(enableModeSigValidator)) {
            revert ValidatorNotInstalled(enableModeSigValidator);
        }
        bytes32 eip712Digest = _hashTypedData(structHash);

        // Use standard IERC-1271/ERC-7739 interface.
        // Even if the validator doesn't support 7739 under the hood, it is still secure,
        // as eip712digest is already built based on 712Domain of this Smart Account
        // This interface should always be exposed by validators as per ERC-7579
        try IValidator(enableModeSigValidator).isValidSignatureWithSender(address(this), eip712Digest, sig[20:]) returns (bytes4 res) {
            return res == ERC1271_MAGICVALUE;
        } catch {
            return false;
        }
    }

    /// @notice Builds the enable mode data hash as per eip712
    /// @param module Module being enabled
    /// @param moduleType Type of the module as per EIP-7579
    /// @param userOpHash Hash of the User Operation
    /// @param initData Module init data.
    /// @return structHash data hash
    function _getEnableModeDataHash(address module, uint256 moduleType, bytes32 userOpHash, bytes calldata initData) internal view returns (bytes32) {
        return keccak256(abi.encode(MODULE_ENABLE_MODE_TYPE_HASH, module, moduleType, userOpHash, keccak256(initData)));
    }

    /// @notice Checks if a module is installed on the smart account.
    /// @param moduleTypeId The module type ID.
    /// @param module The module address.
    /// @param additionalContext Additional context for checking installation.
    /// @return True if the module is installed, false otherwise.
    function _isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) internal view returns (bool) {
        additionalContext;
        if (moduleTypeId == MODULE_TYPE_VALIDATOR) {
            return _isValidatorInstalled(module);
        } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) {
            return _isExecutorInstalled(module);
        } else if (moduleTypeId == MODULE_TYPE_FALLBACK) {
            bytes4 selector;
            if (additionalContext.length >= 4) {
                selector = bytes4(additionalContext[0:4]);
            } else {
                selector = bytes4(0x00000000);
            }
            return _isFallbackHandlerInstalled(selector, module);
        } else if (moduleTypeId == MODULE_TYPE_HOOK) {
            return _isHookInstalled(module);
        } else {
            return false;
        }
    }

    /// @dev Checks if a fallback handler is set for a given selector.
    /// @param selector The function selector to check.
    /// @return True if a fallback handler is set, otherwise false.
    function _isFallbackHandlerInstalled(bytes4 selector) internal view virtual returns (bool) {
        FallbackHandler storage handler = _getAccountStorage().fallbacks[selector];
        return handler.handler != address(0);
    }

    /// @dev Checks if the expected fallback handler is installed for a given selector.
    /// @param selector The function selector to check.
    /// @param expectedHandler The address of the handler expected to be installed.
    /// @return True if the installed handler matches the expected handler, otherwise false.
    function _isFallbackHandlerInstalled(bytes4 selector, address expectedHandler) internal view returns (bool) {
        FallbackHandler storage handler = _getAccountStorage().fallbacks[selector];
        return handler.handler == expectedHandler;
    }

    /// @dev Checks if a validator is currently installed.
    /// @param validator The address of the validator to check.
    /// @return True if the validator is installed, otherwise false.
    function _isValidatorInstalled(address validator) internal view virtual returns (bool) {
        return _getAccountStorage().validators.contains(validator);
    }

    /// @dev Checks if there is at least one validator installed.
    /// @return True if there is at least one validator, otherwise false.
    function _hasValidators() internal view returns (bool) {
        return
            _getAccountStorage().validators.getNext(address(0x01)) != address(0x01) &&
            _getAccountStorage().validators.getNext(address(0x01)) != address(0x00);
    }

    /// @dev Checks if an executor is currently installed.
    /// @param executor The address of the executor to check.
    /// @return True if the executor is installed, otherwise false.
    function _isExecutorInstalled(address executor) internal view virtual returns (bool) {
        return _getAccountStorage().executors.contains(executor);
    }

    /// @dev Checks if a hook is currently installed.
    /// @param hook The address of the hook to check.
    /// @return True if the hook is installed, otherwise false.
    function _isHookInstalled(address hook) internal view returns (bool) {
        return _getHook() == hook;
    }

    /// @dev Retrieves the current hook from the storage.
    /// @return hook The address of the current hook.
    function _getHook() internal view returns (address hook) {
        hook = address(_getAccountStorage().hook);
    }

    function _fallback(bytes calldata callData) private returns (bytes memory result) {
        bool success;
        FallbackHandler storage $fallbackHandler = _getAccountStorage().fallbacks[msg.sig];
        address handler = $fallbackHandler.handler;
        CallType calltype = $fallbackHandler.calltype;

        if (handler != address(0)) {
            //if there's a fallback handler, call it
            if (calltype == CALLTYPE_STATIC) {
                (success, result) = handler.staticcall(ExecLib.get2771CallData(callData));
            } else if (calltype == CALLTYPE_SINGLE) {
                (success, result) = handler.call{ value: msg.value }(ExecLib.get2771CallData(callData));
            } else {
                revert UnsupportedCallType(calltype);
            }

            // Use revert message from fallback handler if the call was not successful
            if (!success) {
                assembly {
                    revert(add(result, 0x20), mload(result))
                }
            }
        } else {
            // If there's no handler, the call can be one of onERCXXXReceived()
            bytes32 s;
            /// @solidity memory-safe-assembly
            assembly {
                s := shr(224, calldataload(0))
                // 0x150b7a02: `onERC721Received(address,address,uint256,bytes)`.
                // 0xf23a6e61: `onERC1155Received(address,address,uint256,uint256,bytes)`.
                // 0xbc197c81: `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
                if or(eq(s, 0x150b7a02), or(eq(s, 0xf23a6e61), eq(s, 0xbc197c81))) {
                    success := true // it is one of onERCXXXReceived
                    result := mload(0x40) //result was set to 0x60 as it was empty, so we need to find a new space for it
                    mstore(result, 0x04) //store length
                    mstore(add(result, 0x20), shl(224, s)) //store calldata
                    mstore(0x40, add(result, 0x24)) //allocate memory
                }
            }
            // if there was no handler and it is not the onERCXXXReceived call, revert
            require(success, MissingFallbackHandler(msg.sig));
        }
    }

    /// @dev Helper function to paginate entries in a SentinelList.
    /// @param list The SentinelList to paginate.
    /// @param cursor The cursor to start paginating from.
    /// @param size The number of entries to return.
    /// @return array The array of addresses in the list.
    /// @return nextCursor The cursor for the next page of entries.
    function _paginate(
        SentinelListLib.SentinelList storage list,
        address cursor,
        uint256 size
    ) private view returns (address[] memory array, address nextCursor) {
        (array, nextCursor) = list.getEntriesPaginated(cursor, size);
    }
}

File 3 of 21 : IModule.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

/// @title Nexus - ERC-7579 Module Base Interface
/// @notice Interface for module management in smart accounts, complying with ERC-7579 specifications.
/// @dev Defines the lifecycle hooks and checks for modules within the smart account architecture.
/// This interface includes methods for installing, uninstalling, and verifying module types and initialization status.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IModule {
    /// @notice Installs the module with necessary initialization data.
    /// @dev Reverts if the module is already initialized.
    /// @param data Arbitrary data required for initializing the module during `onInstall`.
    function onInstall(bytes calldata data) external;

    /// @notice Uninstalls the module and allows for cleanup via arbitrary data.
    /// @dev Reverts if any issues occur that prevent clean uninstallation.
    /// @param data Arbitrary data required for deinitializing the module during `onUninstall`.
    function onUninstall(bytes calldata data) external;

    /// @notice Determines if the module matches a specific module type.
    /// @dev Should return true if the module corresponds to the type ID, false otherwise.
    /// @param moduleTypeId Numeric ID of the module type as per ERC-7579 specifications.
    /// @return True if the module is of the specified type, false otherwise.
    function isModuleType(uint256 moduleTypeId) external view returns (bool);

    /// @notice Checks if the module has been initialized for a specific smart account.
    /// @dev Returns true if initialized, false otherwise.
    /// @param smartAccount Address of the smart account to check for initialization status.
    /// @return True if the module is initialized for the given smart account, false otherwise.
    function isInitialized(address smartAccount) external view returns (bool);
}

File 4 of 21 : IERC7484.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

interface IERC7484 {
    event NewTrustedAttesters();

    /**
     * Allows Smart Accounts - the end users of the registry - to appoint
     * one or many attesters as trusted.
     * @dev this function reverts, if address(0), or duplicates are provided in attesters[]
     *
     * @param threshold The minimum number of attestations required for a module
     *                  to be considered secure.
     * @param attesters The addresses of the attesters to be trusted.
     */
    function trustAttesters(uint8 threshold, address[] calldata attesters) external;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          Check with Registry internal attesters            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    function check(address module) external view;

    function checkForAccount(address smartAccount, address module) external view;

    function check(address module, uint256 moduleType) external view;

    function checkForAccount(address smartAccount, address module, uint256 moduleType) external view;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              Check with external attester(s)               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function check(address module, address[] calldata attesters, uint256 threshold) external view;

    function check(address module, uint256 moduleType, address[] calldata attesters, uint256 threshold) external view;
}

File 5 of 21 : SentinelList.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Sentinel address
address constant SENTINEL = address(0x1);
// Zero address
address constant ZERO_ADDRESS = address(0x0);

/**
 * @title SentinelListLib
 * @dev Library for managing a linked list of addresses
 * @author Rhinestone
 */
library SentinelListLib {
    // Struct to hold the linked list
    struct SentinelList {
        mapping(address => address) entries;
    }

    error LinkedList_AlreadyInitialized();
    error LinkedList_InvalidPage();
    error LinkedList_InvalidEntry(address entry);
    error LinkedList_EntryAlreadyInList(address entry);

    /**
     * Initialize the linked list
     *
     * @param self The linked list
     */
    function init(SentinelList storage self) internal {
        if (alreadyInitialized(self)) revert LinkedList_AlreadyInitialized();
        self.entries[SENTINEL] = SENTINEL;
    }

    /**
     * Check if the linked list is already initialized
     *
     * @param self The linked list
     *
     * @return bool True if the linked list is already initialized
     */
    function alreadyInitialized(SentinelList storage self) internal view returns (bool) {
        return self.entries[SENTINEL] != ZERO_ADDRESS;
    }

    /**
     * Get the next entry in the linked list
     *
     * @param self The linked list
     * @param entry The current entry
     *
     * @return address The next entry
     */
    function getNext(SentinelList storage self, address entry) internal view returns (address) {
        if (entry == ZERO_ADDRESS) {
            revert LinkedList_InvalidEntry(entry);
        }
        return self.entries[entry];
    }

    /**
     * Push a new entry to the linked list
     *
     * @param self The linked list
     * @param newEntry The new entry
     */
    function push(SentinelList storage self, address newEntry) internal {
        if (newEntry == ZERO_ADDRESS || newEntry == SENTINEL) {
            revert LinkedList_InvalidEntry(newEntry);
        }
        if (self.entries[newEntry] != ZERO_ADDRESS) revert LinkedList_EntryAlreadyInList(newEntry);
        self.entries[newEntry] = self.entries[SENTINEL];
        self.entries[SENTINEL] = newEntry;
    }

    /**
     * Safe push a new entry to the linked list
     * @dev This ensures that the linked list is initialized and initializes it if it is not
     *
     * @param self The linked list
     * @param newEntry The new entry
     */
    function safePush(SentinelList storage self, address newEntry) internal {
        if (!alreadyInitialized({ self: self })) {
            init({ self: self });
        }
        push({ self: self, newEntry: newEntry });
    }

    /**
     * Pop an entry from the linked list
     *
     * @param self The linked list
     * @param prevEntry The entry before the entry to pop
     * @param popEntry The entry to pop
     */
    function pop(SentinelList storage self, address prevEntry, address popEntry) internal {
        if (popEntry == ZERO_ADDRESS || popEntry == SENTINEL) {
            revert LinkedList_InvalidEntry(prevEntry);
        }
        if (self.entries[prevEntry] != popEntry) revert LinkedList_InvalidEntry(popEntry);
        self.entries[prevEntry] = self.entries[popEntry];
        self.entries[popEntry] = ZERO_ADDRESS;
    }

    /**
     * Pop all entries from the linked list
     *
     * @param self The linked list
     */
    function popAll(SentinelList storage self) internal {
        address next = self.entries[SENTINEL];
        while (next != ZERO_ADDRESS) {
            address current = next;
            next = self.entries[next];
            self.entries[current] = ZERO_ADDRESS;
        }
    }

    /**
     * Check if the linked list contains an entry
     *
     * @param self The linked list
     * @param entry The entry to check
     *
     * @return bool True if the linked list contains the entry
     */
    function contains(SentinelList storage self, address entry) internal view returns (bool) {
        return SENTINEL != entry && self.entries[entry] != ZERO_ADDRESS;
    }

    /**
     * Get all entries in the linked list
     *
     * @param self The linked list
     * @param start The start entry
     * @param pageSize The page size
     *
     * @return array All entries in the linked list
     * @return next The next entry
     */
    function getEntriesPaginated(
        SentinelList storage self,
        address start,
        uint256 pageSize
    )
        internal
        view
        returns (address[] memory array, address next)
    {
        if (start != SENTINEL && !contains(self, start)) revert LinkedList_InvalidEntry(start);
        if (pageSize == 0) revert LinkedList_InvalidPage();
        // Init array with max page size
        array = new address[](pageSize);

        // Populate return array
        uint256 entryCount = 0;
        next = self.entries[start];
        while (next != ZERO_ADDRESS && next != SENTINEL && entryCount < pageSize) {
            array[entryCount] = next;
            next = self.entries[next];
            entryCount++;
        }

        /**
         * Because of the argument validation, we can assume that the loop will always iterate over
         * the valid entry list values
         *       and the `next` variable will either be an enabled entry or a sentinel address
         * (signalling the end).
         *
         *       If we haven't reached the end inside the loop, we need to set the next pointer to
         * the last element of the entry array
         *       because the `next` variable (which is a entry by itself) acting as a pointer to the
         * start of the next page is neither
         *       incSENTINELrent page, nor will it be included in the next one if you pass it as a
         * start.
         */
        if (next != SENTINEL && entryCount > 0) {
            next = array[entryCount - 1];
        }
        // Set correct size of returned array
        // solhint-disable-next-line no-inline-assembly
        /// @solidity memory-safe-assembly
        assembly {
            mstore(array, entryCount)
        }
    }
}

File 6 of 21 : Storage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { IStorage } from "../interfaces/base/IStorage.sol";

/// @title Nexus - Storage
/// @notice Manages isolated storage spaces for Modular Smart Account in compliance with ERC-7201 standard to ensure collision-resistant storage.
/// @dev Implements the ERC-7201 namespaced storage pattern to maintain secure and isolated storage sections for different states within Nexus suite.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
contract Storage is IStorage {
    /// @custom:storage-location erc7201:biconomy.storage.Nexus
    /// ERC-7201 namespaced via `keccak256(abi.encode(uint256(keccak256(bytes("biconomy.storage.Nexus"))) - 1)) & ~bytes32(uint256(0xff));`
    bytes32 private constant _STORAGE_LOCATION = 0x0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f00;

    /// @dev Utilizes ERC-7201's namespaced storage pattern for isolated storage access. This method computes
    /// the storage slot based on a predetermined location, ensuring collision-resistant storage for contract states.
    /// @custom:storage-location ERC-7201 formula applied to "biconomy.storage.Nexus", facilitating unique
    /// namespace identification and storage segregation, as detailed in the specification.
    /// @return $ The proxy to the `AccountStorage` struct, providing a reference to the namespaced storage slot.
    function _getAccountStorage() internal pure returns (AccountStorage storage $) {
        assembly {
            $.slot := _STORAGE_LOCATION
        }
    }
}

File 7 of 21 : IHook.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { IModule } from "./IModule.sol";

/// @title Hook Management Interface
/// @notice Provides methods for pre-checks and post-checks of transactions to ensure conditions and state consistency.
/// @dev Defines two critical lifecycle hooks in the transaction process: `preCheck` and `postCheck`.
/// These methods facilitate validating conditions prior to execution and verifying state changes afterwards, respectively.
interface IHook is IModule {
    /// @notice Performs checks before a transaction is executed, potentially modifying the transaction context.
    /// @dev This method is called before the execution of a transaction to validate and possibly adjust execution context.
    /// @param msgSender The original sender of the transaction.
    /// @param msgValue The amount of wei sent with the call.
    /// @param msgData The calldata of the transaction.
    /// @return hookData Data that may be used or modified throughout the transaction lifecycle, passed to `postCheck`.
    function preCheck(address msgSender, uint256 msgValue, bytes calldata msgData) external returns (bytes memory hookData);

    /// @notice Performs checks after a transaction is executed to ensure state consistency and log results.
    /// @dev This method is called after the execution of a transaction to verify and react to the execution outcome.
    /// @param hookData Data returned from `preCheck`, containing execution context or modifications.
    function postCheck(bytes calldata hookData) external;
}

File 8 of 21 : IExecutor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { IModule } from "./IModule.sol";

/// @title Nexus - IExecutor Interface
/// @notice Defines the interface for Executor modules within the Nexus Smart Account framework, compliant with the ERC-7579 standard.
/// @dev Extends IModule to include functionalities specific to execution modules.
/// This interface is future-proof, allowing for expansion and integration of advanced features in subsequent versions.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IExecutor is IModule {
    // Future methods for execution management will be defined here to accommodate evolving requirements.
}

File 9 of 21 : IFallback.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { IModule } from "./IModule.sol";

/// @title Nexus - IFallback Interface
/// @notice Defines the interface for Fallback modules within the Nexus Smart Account framework, compliant with the ERC-7579 standard.
/// @dev Extends IModule to include functionalities specific to fallback modules.
/// This interface is future-proof, allowing for expansion and integration of advanced features in subsequent versions.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IFallback is IModule {
    // Future methods for fallback management will be defined here to accommodate evolving blockchain technologies.
}

File 10 of 21 : IValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol";

import { IModule } from "./IModule.sol";

/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IValidator is IModule {
    /// @notice Validates a user operation as per ERC-4337 standard requirements.
    /// @dev Should ensure that the signature and nonce are verified correctly before the transaction is allowed to proceed.
    /// The function returns a status code indicating validation success or failure.
    /// @param userOp The user operation containing transaction details to be validated.
    /// @param userOpHash The hash of the user operation data, used for verifying the signature.
    /// @return status The result of the validation process, typically indicating success or the type of failure.
    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256);

    /// @notice Verifies a signature against a hash, using the sender's address as a contextual check.
    /// @dev Used to confirm the validity of a signature against the specific conditions set by the sender.
    /// @param sender The address from which the operation was initiated, adding an additional layer of validation against the signature.
    /// @param hash The hash of the data signed.
    /// @param data The signature data to validate.
    /// @return magicValue A bytes4 value that corresponds to the ERC-1271 standard, indicating the validity of the signature.
    function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data) external view returns (bytes4);
}

File 11 of 21 : ModeLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

/// @title ModeLib
/// @author zeroknots.eth | rhinestone.wtf
/// To allow smart accounts to be very simple, but allow for more complex execution, A custom mode
/// encoding is used.
///    Function Signature of execute function:
///           function execute(ExecutionMode mode, bytes calldata executionCalldata) external payable;
/// This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and
/// context.
/// NOTE: Simple Account implementations only have to scope for the most significant byte. Account  that
/// implement
/// more complex execution modes may use the entire bytes32.
///
/// |--------------------------------------------------------------------|
/// | CALLTYPE  | EXECTYPE  |   UNUSED   | ModeSelector  |  ModePayload  |
/// |--------------------------------------------------------------------|
/// | 1 byte    | 1 byte    |   4 bytes  | 4 bytes       |   22 bytes    |
/// |--------------------------------------------------------------------|
///
/// CALLTYPE: 1 byte
/// CallType is used to determine how the executeCalldata paramter of the execute function has to be
/// decoded.
/// It can be either single, batch or delegatecall. In the future different calls could be added.
/// CALLTYPE can be used by a validation module to determine how to decode <userOp.callData[36:]>.
///
/// EXECTYPE: 1 byte
/// ExecType is used to determine how the account should handle the execution.
/// It can indicate if the execution should revert on failure or continue execution.
/// In the future more execution modes may be added.
/// Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in
/// a batch fails, the entire batch is reverted
///
/// UNUSED: 4 bytes
/// Unused bytes are reserved for future use.
///
/// ModeSelector: bytes4
/// The "optional" mode selector can be used by account vendors, to implement custom behavior in
/// their accounts.
/// the way a ModeSelector is to be calculated is bytes4(keccak256("vendorname.featurename"))
/// this is to prevent collisions between different vendors, while allowing innovation and the
/// development of new features without coordination between ERC-7579 implementing accounts
///
/// ModePayload: 22 bytes
/// Mode payload is used to pass additional data to the smart account execution, this may be
/// interpreted depending on the ModeSelector
///
/// ExecutionCallData: n bytes
/// single, delegatecall or batch exec abi.encoded as bytes

// Custom type for improved developer experience
type ExecutionMode is bytes32;

type CallType is bytes1;

type ExecType is bytes1;

type ModeSelector is bytes4;

type ModePayload is bytes22;

// Default CallType
CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);
// Batched CallType
CallType constant CALLTYPE_BATCH = CallType.wrap(0x01);

CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);

// @dev Implementing delegatecall is OPTIONAL!
// implement delegatecall with extreme care.
CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);

// @dev default behavior is to revert on failure
// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure
// Since this is value 0x00, no additional encoding is required for simple accounts
ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
// @dev account may elect to change execution behavior. For example "try exec" / "allow fail"
ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);

ModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));
// Example declaration of a custom mode selector
ModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256("default.mode.offset")));

/// @dev ModeLib is a helper library to encode/decode ModeCodes
library ModeLib {
    function decode(
        ExecutionMode mode
    ) internal pure returns (CallType _calltype, ExecType _execType, ModeSelector _modeSelector, ModePayload _modePayload) {
        assembly {
            _calltype := mode
            _execType := shl(8, mode)
            _modeSelector := shl(48, mode)
            _modePayload := shl(80, mode)
        }
    }

    function decodeBasic(ExecutionMode mode) internal pure returns (CallType _calltype, ExecType _execType) {
        assembly {
            _calltype := mode
            _execType := shl(8, mode)
        }
    }

    function encode(CallType callType, ExecType execType, ModeSelector mode, ModePayload payload) internal pure returns (ExecutionMode) {
        return ExecutionMode.wrap(bytes32(abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)));
    }

    function encodeSimpleBatch() internal pure returns (ExecutionMode mode) {
        mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));
    }

    function encodeSimpleSingle() internal pure returns (ExecutionMode mode) {
        mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));
    }

    function encodeTrySingle() internal pure returns (ExecutionMode mode) {
        mode = encode(CALLTYPE_SINGLE, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(0x00));
    }

    function encodeTryBatch() internal pure returns (ExecutionMode mode) {
        mode = encode(CALLTYPE_BATCH, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(0x00));
    }

    function encodeCustom(CallType callType, ExecType execType) internal pure returns (ExecutionMode mode) {
        mode = encode(callType, execType, MODE_DEFAULT, ModePayload.wrap(0x00));
    }

    function getCallType(ExecutionMode mode) internal pure returns (CallType calltype) {
        assembly {
            calltype := mode
        }
    }
}

using { _eqModeSelector as == } for ModeSelector global;
using { _eqCallType as == } for CallType global;
using { _uneqCallType as != } for CallType global;
using { _eqExecType as == } for ExecType global;

function _eqCallType(CallType a, CallType b) pure returns (bool) {
    return CallType.unwrap(a) == CallType.unwrap(b);
}

function _uneqCallType(CallType a, CallType b) pure returns (bool) {
    return CallType.unwrap(a) != CallType.unwrap(b);
}

function _eqExecType(ExecType a, ExecType b) pure returns (bool) {
    return ExecType.unwrap(a) == ExecType.unwrap(b);
}

//slither-disable-next-line dead-code
function _eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {
    return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);
}

File 12 of 21 : ExecLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import { Execution } from "../types/DataTypes.sol";

/// @title ExecutionLib
/// @author zeroknots.eth | rhinestone.wtf
/// Helper Library for decoding Execution calldata
/// malloc for memory allocation is bad for gas. use this assembly instead
library ExecLib {
    error InvalidBatchCallData();

    function get2771CallData(bytes calldata cd) internal view returns (bytes memory callData) {
        /// @solidity memory-safe-assembly
        (cd);
        assembly {
            // as per solidity docs
            function allocate(length) -> pos {
                pos := mload(0x40)
                mstore(0x40, add(pos, length))
            }

            callData := allocate(add(calldatasize(), 0x20)) //allocate extra 0x20 to store length
            mstore(callData, add(calldatasize(), 0x14)) //store length, extra 0x14 is for msg.sender address
            calldatacopy(add(callData, 0x20), 0, calldatasize())

            // The msg.sender address is shifted to the left by 12 bytes to remove the padding
            // Then the address without padding is stored right after the calldata
            let senderPtr := allocate(0x14)
            mstore(senderPtr, shl(96, caller()))
        }
    }

    function decodeBatch(bytes calldata callData) internal view returns (Execution[] calldata executionBatch) {
        /*
         * Batch Call Calldata Layout
         * Offset (in bytes)    | Length (in bytes) | Contents
         * 0x0                  | 0x4               | bytes4 function selector
         * 0x4                  | -                 | abi.encode(IERC7579Execution.Execution[])
         */
        assembly ("memory-safe") {
            let dataPointer := add(callData.offset, calldataload(callData.offset))
            // Extract the ERC7579 Executions
            executionBatch.offset := add(dataPointer, 32)
            executionBatch.length := calldataload(dataPointer)
        }
    }   

    function encodeBatch(Execution[] memory executions) internal pure returns (bytes memory callData) {
        callData = abi.encode(executions);
    }

    function decodeSingle(bytes calldata executionCalldata) internal pure returns (address target, uint256 value, bytes calldata callData) {
        target = address(bytes20(executionCalldata[0:20]));
        value = uint256(bytes32(executionCalldata[20:52]));
        callData = executionCalldata[52:];
    }

    function decodeDelegateCall(bytes calldata executionCalldata) internal pure returns (address delegate, bytes calldata callData) {
        // destructure executionCallData according to single exec
        delegate = address(uint160(bytes20(executionCalldata[0:20])));
        callData = executionCalldata[20:];
    }

    function encodeSingle(address target, uint256 value, bytes memory callData) internal pure returns (bytes memory userOpCalldata) {
        userOpCalldata = abi.encodePacked(target, value, callData);
    }
}

File 13 of 21 : LocalCallDataParserLib.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;

library LocalCallDataParserLib {
    /// @dev Parses the `userOp.signature` to extract the module type, module initialization data,
    ///      enable mode signature, and user operation signature. The `userOp.signature` must be
    ///      encoded in a specific way to be parsed correctly.
    /// @param packedData The packed signature data, typically coming from `userOp.signature`.
    /// @return module The address of the module.
    /// @return moduleType The type of module as a `uint256`.
    /// @return moduleInitData Initialization data specific to the module.
    /// @return enableModeSignature Signature used to enable the module mode.
    /// @return userOpSignature The remaining user operation signature data.
    function parseEnableModeData(
        bytes calldata packedData
    )
        internal
        pure
        returns (
            address module,
            uint256 moduleType,
            bytes calldata moduleInitData,
            bytes calldata enableModeSignature,
            bytes calldata userOpSignature
        )
    {
        uint256 p;
        assembly ("memory-safe") {
            p := packedData.offset
            module := shr(96, calldataload(p))

            p := add(p, 0x14)
            moduleType := calldataload(p)

            moduleInitData.length := shr(224, calldataload(add(p, 0x20)))
            moduleInitData.offset := add(p, 0x24)
            p := add(moduleInitData.offset, moduleInitData.length)

            enableModeSignature.length := shr(224, calldataload(p))
            enableModeSignature.offset := add(p, 0x04)
            p := sub(add(enableModeSignature.offset, enableModeSignature.length), packedData.offset)
        }
        userOpSignature = packedData[p:];
    }

    /// @dev Parses the data to obtain types and initdata's for Multi Type module install mode
    /// @param initData Multi Type module init data, abi.encoded
    function parseMultiTypeInitData(bytes calldata initData) internal pure returns (uint256[] calldata types, bytes[] calldata initDatas) {
        // equivalent of:
        // (types, initDatas) = abi.decode(initData,(uint[],bytes[]))
        assembly ("memory-safe") {
            let offset := initData.offset
            let baseOffset := offset
            let dataPointer := add(baseOffset, calldataload(offset))

            types.offset := add(dataPointer, 32)
            types.length := calldataload(dataPointer)
            offset := add(offset, 32)

            dataPointer := add(baseOffset, calldataload(offset))
            initDatas.offset := add(dataPointer, 32)
            initDatas.length := calldataload(dataPointer)
        }
    }
}

File 14 of 21 : IModuleManagerEventsAndErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { CallType } from "../../lib/ModeLib.sol";

/// @title ERC-7579 Module Manager Events and Errors Interface
/// @notice Provides event and error definitions for actions related to module management in smart accounts.
/// @dev Used by IModuleManager to define the events and errors associated with the installation and management of modules.
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IModuleManagerEventsAndErrors {
    /// @notice Emitted when a module is installed onto a smart account.
    /// @param moduleTypeId The identifier for the type of module installed.
    /// @param module The address of the installed module.
    event ModuleInstalled(uint256 moduleTypeId, address module);

    /// @notice Emitted when a module is uninstalled from a smart account.
    /// @param moduleTypeId The identifier for the type of module uninstalled.
    /// @param module The address of the uninstalled module.
    event ModuleUninstalled(uint256 moduleTypeId, address module);

    /// @notice Thrown when attempting to remove the last validator.
    error CanNotRemoveLastValidator();

    /// @dev Thrown when the specified module address is not recognized as valid.
    error ValidatorNotInstalled(address module);

    /// @dev Thrown when there is no installed validator detected.
    error NoValidatorInstalled();

    /// @dev Thrown when the specified module address is not recognized as valid.
    error InvalidModule(address module);

    /// @dev Thrown when an invalid module type identifier is provided.
    error InvalidModuleTypeId(uint256 moduleTypeId);

    /// @dev Thrown when there is an attempt to install a module that is already installed.
    error ModuleAlreadyInstalled(uint256 moduleTypeId, address module);

    /// @dev Thrown when an operation is performed by an unauthorized operator.
    error UnauthorizedOperation(address operator);

    /// @dev Thrown when there is an attempt to uninstall a module that is not installed.
    error ModuleNotInstalled(uint256 moduleTypeId, address module);

    /// @dev Thrown when a module address is set to zero.
    error ModuleAddressCanNotBeZero();

    /// @dev Thrown when a post-check fails after hook execution.
    error HookPostCheckFailed();

    /// @dev Thrown when there is an attempt to install a hook while another is already installed.
    error HookAlreadyInstalled(address currentHook);

    /// @dev Thrown when there is an attempt to install a fallback handler for a selector already having one.
    error FallbackAlreadyInstalledForSelector(bytes4 selector);

    /// @dev Thrown when there is an attempt to uninstall a fallback handler for a selector that does not have one installed.
    error FallbackNotInstalledForSelector(bytes4 selector);

    /// @dev Thrown when a fallback handler fails to uninstall properly.
    error FallbackHandlerUninstallFailed();

    /// @dev Thrown when no fallback handler is available for a given selector.
    error MissingFallbackHandler(bytes4 selector);

    /// @dev Thrown when Invalid data is provided for MultiType install flow
    error InvalidInput();

    /// @dev Thrown when unable to validate Module Enable Mode signature
    error EnableModeSigError();

    /// Error thrown when account installs/uninstalls module with mismatched input `moduleTypeId`
    error MismatchModuleTypeId(uint256 moduleTypeId);

    /// @dev Thrown when there is an attempt to install a forbidden selector as a fallback handler.
    error FallbackSelectorForbidden();

    /// @dev Thrown when there is an attempt to install a fallback handler with an invalid calltype for a given selector.
    error FallbackCallTypeInvalid();

    /// @notice Error thrown when an execution with an unsupported CallType was made.
    /// @param callType The unsupported call type.
    error UnsupportedCallType(CallType callType);
}

File 15 of 21 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

// Magic value for ERC-1271 valid signature
bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e;

// Value indicating an invalid ERC-1271 signature
bytes4 constant ERC1271_INVALID = 0xFFFFFFFF;

// Value indicating successful validation
uint256 constant VALIDATION_SUCCESS = 0;

// Value indicating failed validation
uint256 constant VALIDATION_FAILED = 1;

// Module type identifier for Multitype install
uint256 constant MODULE_TYPE_MULTI = 0;

// Module type identifier for validators
uint256 constant MODULE_TYPE_VALIDATOR = 1;

// Module type identifier for executors
uint256 constant MODULE_TYPE_EXECUTOR = 2;

// Module type identifier for fallback handlers
uint256 constant MODULE_TYPE_FALLBACK = 3;

// Module type identifier for hooks
uint256 constant MODULE_TYPE_HOOK = 4;

string constant MODULE_ENABLE_MODE_NOTATION = "ModuleEnableMode(address module,uint256 moduleType,bytes32 userOpHash,bytes32 initDataHash)";
bytes32 constant MODULE_ENABLE_MODE_TYPE_HASH = keccak256(bytes(MODULE_ENABLE_MODE_NOTATION));

// Validation modes
bytes1 constant MODE_VALIDATION = 0x00;
bytes1 constant MODE_MODULE_ENABLE = 0x01;

bytes4 constant SUPPORTS_ERC7739 = 0x77390000;
bytes4 constant SUPPORTS_ERC7739_V1 = 0x77390001;

File 16 of 21 : EIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CONSTANTS AND IMMUTABLES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    uint256 private immutable _cachedThis;
    uint256 private immutable _cachedChainId;
    bytes32 private immutable _cachedNameHash;
    bytes32 private immutable _cachedVersionHash;
    bytes32 private immutable _cachedDomainSeparator;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CONSTRUCTOR                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Cache the hashes for cheaper runtime gas costs.
    /// In the case of upgradeable contracts (i.e. proxies),
    /// or if the chain id changes due to a hard fork,
    /// the domain separator will be seamlessly calculated on-the-fly.
    constructor() {
        _cachedThis = uint256(uint160(address(this)));
        _cachedChainId = block.chainid;

        string memory name;
        string memory version;
        if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
        bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
        bytes32 versionHash =
            _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
        _cachedNameHash = nameHash;
        _cachedVersionHash = versionHash;

        bytes32 separator;
        if (!_domainNameAndVersionMayChange()) {
            /// @solidity memory-safe-assembly
            assembly {
                let m := mload(0x40) // Load the free memory pointer.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), versionHash)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                separator := keccak256(m, 0xa0)
            }
        }
        _cachedDomainSeparator = separator;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   FUNCTIONS TO OVERRIDE                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Please override this function to return the domain name and version.
    /// ```
    ///     function _domainNameAndVersion()
    ///         internal
    ///         pure
    ///         virtual
    ///         returns (string memory name, string memory version)
    ///     {
    ///         name = "Solady";
    ///         version = "1";
    ///     }
    /// ```
    ///
    /// Note: If the returned result may change after the contract has been deployed,
    /// you must override `_domainNameAndVersionMayChange()` to return true.
    function _domainNameAndVersion()
        internal
        view
        virtual
        returns (string memory name, string memory version);

    /// @dev Returns if `_domainNameAndVersion()` may change
    /// after the contract has been deployed (i.e. after the constructor).
    /// Default: false.
    function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _domainSeparator() internal view virtual returns (bytes32 separator) {
        if (_domainNameAndVersionMayChange()) {
            separator = _buildDomainSeparator();
        } else {
            separator = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
        }
    }

    /// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
    /// given `structHash`, as defined in
    /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    ///
    /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
    /// ```
    ///     bytes32 digest = _hashTypedData(keccak256(abi.encode(
    ///         keccak256("Mail(address to,string contents)"),
    ///         mailTo,
    ///         keccak256(bytes(mailContents))
    ///     )));
    ///     address signer = ECDSA.recover(digest, signature);
    /// ```
    function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
        // We will use `digest` to store the domain separator to save a bit of gas.
        if (_domainNameAndVersionMayChange()) {
            digest = _buildDomainSeparator();
        } else {
            digest = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the digest.
            mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
            mstore(0x1a, digest) // Store the domain separator.
            mstore(0x3a, structHash) // Store the struct hash.
            digest := keccak256(0x18, 0x42)
            // Restore the part of the free memory slot that was overwritten.
            mstore(0x3a, 0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    EIP-5267 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev See: https://eips.ethereum.org/EIPS/eip-5267
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        fields = hex"0f"; // `0b01111`.
        (name, version) = _domainNameAndVersion();
        chainId = block.chainid;
        verifyingContract = address(this);
        salt = salt; // `bytes32(0)`.
        extensions = extensions; // `new uint256[](0)`.
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _buildDomainSeparator() private view returns (bytes32 separator) {
        // We will use `separator` to store the name hash to save a bit of gas.
        bytes32 versionHash;
        if (_domainNameAndVersionMayChange()) {
            (string memory name, string memory version) = _domainNameAndVersion();
            separator = keccak256(bytes(name));
            versionHash = keccak256(bytes(version));
        } else {
            separator = _cachedNameHash;
            versionHash = _cachedVersionHash;
        }
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), separator) // Name hash.
            mstore(add(m, 0x40), versionHash)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            separator := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns if the cached domain separator has been invalidated.
    function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
        uint256 cachedChainId = _cachedChainId;
        uint256 cachedThis = _cachedThis;
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
        }
    }
}

File 17 of 21 : ExcessivelySafeCall.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.7.6;

library ExcessivelySafeCall {
    uint256 constant LOW_28_MASK =
        0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    /// @notice Use when you _really_ really _really_ don't trust the called
    /// contract. This prevents the called contract from causing reversion of
    /// the caller in as many ways as we can.
    /// @dev The main difference between this and a solidity low-level call is
    /// that we limit the number of bytes that the callee can cause to be
    /// copied to caller memory. This prevents stupid things like malicious
    /// contracts returning 10,000,000 bytes causing a local OOG when copying
    /// to memory.
    /// @param _target The address to call
    /// @param _gas The amount of gas to forward to the remote contract
    /// @param _value The value in wei to send to the remote contract
    /// @param _maxCopy The maximum number of bytes of returndata to copy
    /// to memory.
    /// @param _calldata The data to send to the remote contract
    /// @return success and returndata, as `.call()`. Returndata is capped to
    /// `_maxCopy` bytes.
    function excessivelySafeCall(
        address _target,
        uint256 _gas,
        uint256 _value,
        uint16 _maxCopy,
        bytes memory _calldata
    ) internal returns (bool, bytes memory) {
        // set up for assembly call
        uint256 _toCopy;
        bool _success;
        bytes memory _returnData = new bytes(_maxCopy);
        // dispatch message to recipient
        // by assembly calling "handle" function
        // we call via assembly to avoid memcopying a very large returndata
        // returned by a malicious contract
        assembly {
            _success := call(
                _gas, // gas
                _target, // recipient
                _value, // ether value
                add(_calldata, 0x20), // inloc
                mload(_calldata), // inlen
                0, // outloc
                0 // outlen
            )
            // limit our copy to 256 bytes
            _toCopy := returndatasize()
            if gt(_toCopy, _maxCopy) {
                _toCopy := _maxCopy
            }
            // Store the length of the copied bytes
            mstore(_returnData, _toCopy)
            // copy the bytes from returndata[0:_toCopy]
            returndatacopy(add(_returnData, 0x20), 0, _toCopy)
        }
        return (_success, _returnData);
    }

    /// @notice Use when you _really_ really _really_ don't trust the called
    /// contract. This prevents the called contract from causing reversion of
    /// the caller in as many ways as we can.
    /// @dev The main difference between this and a solidity low-level call is
    /// that we limit the number of bytes that the callee can cause to be
    /// copied to caller memory. This prevents stupid things like malicious
    /// contracts returning 10,000,000 bytes causing a local OOG when copying
    /// to memory.
    /// @param _target The address to call
    /// @param _gas The amount of gas to forward to the remote contract
    /// @param _maxCopy The maximum number of bytes of returndata to copy
    /// to memory.
    /// @param _calldata The data to send to the remote contract
    /// @return success and returndata, as `.call()`. Returndata is capped to
    /// `_maxCopy` bytes.
    function excessivelySafeStaticCall(
        address _target,
        uint256 _gas,
        uint16 _maxCopy,
        bytes memory _calldata
    ) internal view returns (bool, bytes memory) {
        // set up for assembly call
        uint256 _toCopy;
        bool _success;
        bytes memory _returnData = new bytes(_maxCopy);
        // dispatch message to recipient
        // by assembly calling "handle" function
        // we call via assembly to avoid memcopying a very large returndata
        // returned by a malicious contract
        assembly {
            _success := staticcall(
                _gas, // gas
                _target, // recipient
                add(_calldata, 0x20), // inloc
                mload(_calldata), // inlen
                0, // outloc
                0 // outlen
            )
            // limit our copy to 256 bytes
            _toCopy := returndatasize()
            if gt(_toCopy, _maxCopy) {
                _toCopy := _maxCopy
            }
            // Store the length of the copied bytes
            mstore(_returnData, _toCopy)
            // copy the bytes from returndata[0:_toCopy]
            returndatacopy(add(_returnData, 0x20), 0, _toCopy)
        }
        return (_success, _returnData);
    }

    /**
     * @notice Swaps function selectors in encoded contract calls
     * @dev Allows reuse of encoded calldata for functions with identical
     * argument types but different names. It simply swaps out the first 4 bytes
     * for the new selector. This function modifies memory in place, and should
     * only be used with caution.
     * @param _newSelector The new 4-byte selector
     * @param _buf The encoded contract args
     */
    function swapSelector(bytes4 _newSelector, bytes memory _buf)
        internal
        pure
    {
        require(_buf.length >= 4);
        uint256 _mask = LOW_28_MASK;
        assembly {
            // load the first word of
            let _word := mload(add(_buf, 0x20))
            // mask out the top 4 bytes
            // /x
            _word := and(_word, _mask)
            _word := or(_newSelector, _word)
            mstore(add(_buf, 0x20), _word)
        }
    }
}

File 18 of 21 : RegistryAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import { IERC7484 } from "../interfaces/IERC7484.sol";

/// @title RegistryAdapter
/// @notice This contract provides an interface for interacting with an ERC-7484 compliant registry.
/// @dev The registry feature is opt-in, allowing the smart account owner to select and trust specific attesters.
abstract contract RegistryAdapter {
    IERC7484 public registry;

    /// @notice Emitted when a new ERC-7484 registry is configured for the account.
    /// @param registry The configured registry contract.
    event ERC7484RegistryConfigured(IERC7484 indexed registry);

    /// @notice Modifier to check if a module meets the required attestations in the registry.
    /// @param module The module to check.
    /// @param moduleType The type of the module to verify in the registry.
    modifier withRegistry(address module, uint256 moduleType) {
        _checkRegistry(module, moduleType);
        _;
    }

    /// @notice Configures the ERC-7484 registry and sets trusted attesters.
    /// @param newRegistry The new registry contract to use.
    /// @param attesters The list of attesters to trust.
    /// @param threshold The number of attestations required.
    function _configureRegistry(IERC7484 newRegistry, address[] calldata attesters, uint8 threshold) internal {
        registry = newRegistry;
        if (address(newRegistry) != address(0)) {
            newRegistry.trustAttesters(threshold, attesters);
        }
        emit ERC7484RegistryConfigured(newRegistry);
    }

    /// @notice Checks the registry to ensure sufficient valid attestations for a module.
    /// @param module The module to check.
    /// @param moduleType The type of the module to verify in the registry.
    /// @dev Reverts if the required attestations are not met.
    function _checkRegistry(address module, uint256 moduleType) internal view {
        IERC7484 moduleRegistry = registry;
        if (address(moduleRegistry) != address(0)) {
            // This will revert if attestations or the threshold are not met.
            moduleRegistry.check(module, moduleType);
        }
    }
}

File 19 of 21 : IStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

import { SentinelListLib } from "sentinellist/SentinelList.sol";

import { IHook } from "../modules/IHook.sol";
import { CallType } from "../../lib/ModeLib.sol";

/// @title Nexus - IStorage Interface
/// @notice Provides structured storage for Modular Smart Account under the Nexus suite, compliant with ERC-7579 and ERC-4337.
/// @dev Manages structured storage using SentinelListLib for validators and executors, and a mapping for fallback handlers.
/// This interface utilizes ERC-7201 storage location practices to ensure isolated and collision-resistant storage spaces within smart contracts.
/// It is designed to support dynamic execution and modular management strategies essential for advanced smart account architectures.
/// @custom:storage-location erc7201:biconomy.storage.Nexus
/// @author @livingrockrises | Biconomy | [email protected]
/// @author @aboudjem | Biconomy | [email protected]
/// @author @filmakarov | Biconomy | [email protected]
/// @author @zeroknots | Rhinestone.wtf | zeroknots.eth
/// Special thanks to the Solady team for foundational contributions: https://github.com/Vectorized/solady
interface IStorage {
    /// @notice Struct storing validators and executors using Sentinel lists, and fallback handlers via mapping.
    struct AccountStorage {
        SentinelListLib.SentinelList validators; ///< List of validators, initialized upon contract deployment.
        SentinelListLib.SentinelList executors; ///< List of executors, similarly initialized.
        mapping(bytes4 => FallbackHandler) fallbacks; ///< Mapping of selectors to their respective fallback handlers.
        IHook hook; ///< Current hook module associated with this account.
        mapping(address hook => uint256) emergencyUninstallTimelock; ///< Mapping of hooks to requested timelocks.
    }

    /// @notice Defines a fallback handler with an associated handler address and a call type.
    struct FallbackHandler {
        address handler; ///< The address of the fallback function handler.
        CallType calltype; ///< The type of call this handler supports (e.g., static or call).
    }
}

File 20 of 21 : PackedUserOperation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

/**
 * User Operation struct
 * @param sender                - The sender account of this request.
 * @param nonce                 - Unique value the sender uses to verify it is not a replay.
 * @param initCode              - If set, the account contract will be created by this constructor/
 * @param callData              - The method call to execute on this account.
 * @param accountGasLimits      - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
 * @param preVerificationGas    - Gas not calculated by the handleOps method, but added to the gas paid.
 *                                Covers batch overhead.
 * @param gasFees               - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.
 * @param paymasterAndData      - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data
 *                                The paymaster will pay for the transaction instead of the sender.
 * @param signature             - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.
 */
struct PackedUserOperation {
    address sender;
    uint256 nonce;
    bytes initCode;
    bytes callData;
    bytes32 accountGasLimits;
    uint256 preVerificationGas;
    bytes32 gasFees;
    bytes paymasterAndData;
    bytes signature;
}

File 21 of 21 : DataTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

// ──────────────────────────────────────────────────────────────────────────────
//     _   __    _  __
//    / | / /__ | |/ /_  _______
//   /  |/ / _ \|   / / / / ___/
//  / /|  /  __/   / /_/ (__  )
// /_/ |_/\___/_/|_\__,_/____/
//
// ──────────────────────────────────────────────────────────────────────────────
// Nexus: A suite of contracts for Modular Smart Accounts compliant with ERC-7579 and ERC-4337, developed by Biconomy.
// Learn more at https://biconomy.io. To report security issues, please contact us at: [email protected]

/// @title Execution
/// @notice Struct to encapsulate execution data for a transaction
struct Execution {
    /// @notice The target address for the transaction
    address target;
    /// @notice The value in wei to send with the transaction
    uint256 value;
    /// @notice The calldata for the transaction
    bytes callData;
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "forge-std/=node_modules/forge-std/src/",
    "account-abstraction/=node_modules/account-abstraction/contracts/",
    "solady/=node_modules/solady/src/",
    "excessively-safe-call/=node_modules/excessively-safe-call/src/",
    "sentinellist/=node_modules/sentinellist/src/",
    "solarray/=node_modules/solarray/src/",
    "erc7739Validator/=node_modules/erc7739-validator-base/src/",
    "@ERC4337/=node_modules/@ERC4337/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "@prb/=node_modules/@prb/",
    "@prb/math/=node_modules/erc7739-validator-base/node_modules/@prb/math/src/",
    "@rhinestone/=node_modules/@rhinestone/",
    "@safe-global/=node_modules/@safe-global/",
    "@zerodev/=node_modules/@zerodev/",
    "ExcessivelySafeCall/=node_modules/erc7739-validator-base/node_modules/excessively-safe-call/src/",
    "account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/",
    "ds-test/=node_modules/ds-test/",
    "enumerablemap/=node_modules/enumerablemap/",
    "enumerableset4337/=node_modules/erc7739-validator-base/node_modules/enumerablemap/src/",
    "erc4337-validation/=node_modules/erc7739-validator-base/node_modules/@rhinestone/erc4337-validation/src/",
    "erc7579/=node_modules/erc7579/",
    "erc7739-validator-base/=node_modules/erc7739-validator-base/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "kernel/=node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/",
    "module-bases/=node_modules/erc7739-validator-base/node_modules/@rhinestone/module-bases/src/",
    "modulekit/=node_modules/modulekit/",
    "registry/=node_modules/modulekit/node_modules/@rhinestone/registry/src/",
    "safe7579/=node_modules/erc7739-validator-base/node_modules/@rhinestone/safe7579/src/",
    "stringutils/=node_modules/stringutils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"CanNotRemoveLastValidator","type":"error"},{"inputs":[],"name":"EnableModeSigError","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"FallbackAlreadyInstalledForSelector","type":"error"},{"inputs":[],"name":"FallbackCallTypeInvalid","type":"error"},{"inputs":[],"name":"FallbackHandlerUninstallFailed","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"FallbackNotInstalledForSelector","type":"error"},{"inputs":[],"name":"FallbackSelectorForbidden","type":"error"},{"inputs":[{"internalType":"address","name":"currentHook","type":"address"}],"name":"HookAlreadyInstalled","type":"error"},{"inputs":[],"name":"HookPostCheckFailed","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"InvalidModule","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"InvalidModuleTypeId","type":"error"},{"inputs":[{"internalType":"address","name":"entry","type":"address"}],"name":"LinkedList_EntryAlreadyInList","type":"error"},{"inputs":[{"internalType":"address","name":"entry","type":"address"}],"name":"LinkedList_InvalidEntry","type":"error"},{"inputs":[],"name":"LinkedList_InvalidPage","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"MismatchModuleTypeId","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"MissingFallbackHandler","type":"error"},{"inputs":[],"name":"ModuleAddressCanNotBeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"}],"name":"ModuleAlreadyInstalled","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"}],"name":"ModuleNotInstalled","type":"error"},{"inputs":[],"name":"NoValidatorInstalled","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"UnauthorizedOperation","type":"error"},{"inputs":[{"internalType":"CallType","name":"callType","type":"bytes1"}],"name":"UnsupportedCallType","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"ValidatorNotInstalled","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC7484","name":"registry","type":"address"}],"name":"ERC7484RegistryConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleUninstalled","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getActiveHook","outputs":[{"internalType":"address","name":"hook","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cursor","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"getExecutorsPaginated","outputs":[{"internalType":"address[]","name":"array","type":"address[]"},{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getFallbackHandlerBySelector","outputs":[{"internalType":"CallType","name":"","type":"bytes1"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"executors","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"hook","type":"tuple"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"fallbacks","type":"tuple[]"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"getInitNexusCalldata","outputs":[{"internalType":"bytes","name":"init","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"hook","type":"tuple"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"getInitNexusScopedCalldata","outputs":[{"internalType":"bytes","name":"init","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"validator","type":"tuple"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"getInitNexusWithSingleValidatorCalldata","outputs":[{"internalType":"bytes","name":"init","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cursor","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"getValidatorsPaginated","outputs":[{"internalType":"address[]","name":"array","type":"address[]"},{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"executors","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"hook","type":"tuple"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"fallbacks","type":"tuple[]"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"initNexus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"hook","type":"tuple"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"initNexusScoped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IModule","name":"validator","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"initNexusWithSingleValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IERC7484","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

610120604052348015600f575f5ffd5b50306080524660a0526060806061604080518082018252600e81526d04e65787573426f6f7473747261760941b602080830191909152825180840190935260058352640312e302e360dc1b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a09020610100525060c99050565b60805160a05160c05160e051610100516122d76100f75f395f50505f50505f50505f50505f50506122d75ff3fe6080604052600436106100ca575f3560e01c8063837b892e116100735780639e2533ed1161004d5780639e2533ed14610425578063d6fe71f114610444578063ea5f61d014610463576100d1565b8063837b892e146103b357806384b0196e146103df57806385a924cc14610406576100d1565b806355470cf1116100a457806355470cf1146103495780635faac46b146103685780637b10399914610395576100d1565b806301fe9ff2146102455780630a664dba14610266578063481ddd2314610297576100d1565b366100d157005b5f3660605f6101077f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b90506001600160a01b038116610128576101218484610482565b9150610239565b6040517fd68f60250000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063d68f6025906101759033903490869036906004016118b1565b5f604051808303815f875af1158015610190573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101b791908101906118f7565b90506101c38585610482565b92506040517f173bf7da0000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063173bf7da9061020a9084906004016119d8565b5f604051808303815f87803b158015610221575f5ffd5b505af1158015610233573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b348015610250575f5ffd5b5061026461025f366004611a69565b6106b2565b005b348015610271575f5ffd5b5061027a6106d2565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a2575f5ffd5b506103216102b1366004611b3a565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b0390911660208301520161028e565b348015610354575f5ffd5b50610264610363366004611b77565b610709565b348015610373575f5ffd5b50610387610382366004611beb565b6107d2565b60405161028e929190611c15565b3480156103a0575f5ffd5b505f5461027a906001600160a01b031681565b3480156103be575f5ffd5b506103d26103cd366004611c74565b61080b565b60405161028e91906119d8565b3480156103ea575f5ffd5b506103f36108a0565b60405161028e9796959493929190611d01565b348015610411575f5ffd5b506103d2610420366004611b77565b610948565b348015610430575f5ffd5b506103d261043f366004611d9b565b6109d1565b34801561044f575f5ffd5b5061026461045e366004611d9b565b610a66565b34801561046e575f5ffd5b5061038761047d366004611beb565b610c92565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b8115610616576104e981607f60f91b610cc0565b1561055657816001600160a01b03166105028888610cd7565b60405161050f9190611eb4565b5f60405180830381855afa9150503d805f8114610547576040519150601f19603f3d011682016040523d82523d5f602084013e61054c565b606091505b5095509350610604565b610560815f610cc0565b156105c157816001600160a01b03163461057a8989610cd7565b6040516105879190611eb4565b5f6040518083038185875af1925050503d805f8114610547576040519150601f19603f3d011682016040523d82523d5f602084013e61054c565b6040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526001600160f81b0319821660048201526024015b60405180910390fd5b8361061157845160208601fd5b6106a8565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561065557600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f3516856106a5576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105fb565b50505b5050505092915050565b6106be84848484610d0c565b6106c9878787610deb565b50505050505050565b5f6107047f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b905090565b61071584848484610d0c565b5f5b868110156107935761078b88888381811061073457610734611eca565b90506020028101906107469190611ede565b610754906020810190611efc565b89898481811061076657610766611eca565b90506020028101906107789190611ede565b610786906020810190611f17565b610deb565b600101610717565b505f6107a26020870187611efc565b6001600160a01b0316146106c9576106c96107c06020870187611efc565b6107cd6020880188611f17565b610f0b565b60605f6108007f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0085856110ca565b909590945092505050565b606030806301fe9ff261082160208a018a611efc565b61082e60208b018b611f17565b8a8a8a8a6040516024016108489796959493929190611fa2565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610886929190611ffe565b604051602081830303815290604052905095945050505050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f808083610936604080518082018252600e81527f4e65787573426f6f7473747261700000000000000000000000000000000000006020808301919091528251808401909352600583527f312e302e300000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b606030306001600160a01b03166355470cf18a8a8a8a8a8a8a6040516024016109779796959493929190612108565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506040516020016109b5929190611ffe565b6040516020818303038152906040529050979650505050505050565b606030306001600160a01b031663d6fe71f18e8e8e8e8e8e8e8e8e8e8e604051602401610a089b9a99989796959493929190612151565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610a46929190611ffe565b60405160208183030381529060405290509b9a5050505050505050505050565b610a7284848484610d0c565b5f5b8a811015610acb57610ac38c8c83818110610a9157610a91611eca565b9050602002810190610aa39190611ede565b610ab1906020810190611efc565b8d8d8481811061076657610766611eca565b600101610a74565b505f5b88811015610b8b575f8a8a83818110610ae957610ae9611eca565b9050602002810190610afb9190611ede565b610b09906020810190611efc565b6001600160a01b031614610b8357610b838a8a83818110610b2c57610b2c611eca565b9050602002810190610b3e9190611ede565b610b4c906020810190611efc565b8b8b84818110610b5e57610b5e611eca565b9050602002810190610b709190611ede565b610b7e906020810190611f17565b6110e4565b600101610ace565b505f610b9a6020890189611efc565b6001600160a01b031614610bc557610bc5610bb86020890189611efc565b6107cd60208a018a611f17565b5f5b85811015610c84575f878783818110610be257610be2611eca565b9050602002810190610bf49190611ede565b610c02906020810190611efc565b6001600160a01b031614610c7c57610c7c878783818110610c2557610c25611eca565b9050602002810190610c379190611ede565b610c45906020810190611efc565b888884818110610c5757610c57611eca565b9050602002810190610c699190611ede565b610c77906020810190611f17565b6111a2565b600101610bc7565b505050505050505050505050565b60605f6108007f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856110ca565b6001600160f81b0319828116908216145b92915050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915515610db2576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e190610d84908490879087906004016121e0565b5f604051808303815f87803b158015610d9b575f5ffd5b505af1158015610dad573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b826001610df8828261150d565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610e3b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5f91906121fc565b610e7f576040516369c9a24560e11b8152600160048201526024016105fb565b610ea97f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0086611594565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe7090610ed7908790879060040161221b565b5f604051808303815f87803b158015610eee575f5ffd5b505af1158015610f00573d5f5f3e3d5ffd5b505050505050505050565b826004610f18828261150d565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610f5a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f7e91906121fc565b610f9d576040516369c9a24560e11b81526004818101526024016105fb565b5f610fcf7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b9050806001600160a01b0381161561101f576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016105fb565b507f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe7090611095908890889060040161221b565b5f604051808303815f87803b1580156110ac575f5ffd5b505af11580156110be573d5f5f3e3d5ffd5b50505050505050505050565b60605f6110d885858561168e565b90969095509350505050565b8260026110f1828261150d565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015611134573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061115891906121fc565b611178576040516369c9a24560e11b8152600260048201526024016105fb565b610ea97f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0186611594565b8260036111af828261150d565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa1580156111f2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061121691906121fc565b611236576040516369c9a24560e11b8152600360048201526024016105fb565b5f611244600482868861222e565b61124d91612255565b90505f8585600481811061126357611263611eca565b9050013560f81c60f81b905061127c815f60f81b610cc0565b80611290575061129081607f60f91b610cc0565b6112c6576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112d4866005818a61222e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b148061135257506001600160e01b031983167f8a91b0e300000000000000000000000000000000000000000000000000000000145b8061136557506001600160e01b03198316155b1561139c576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615611423576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105fb565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169316929092179190911790915590516306d61fe760e41b8152636d61fe70906114e49084906004016119d8565b5f604051808303815f87803b1580156114fb575f5ffd5b505af1158015610c84573d5f5f3e3d5ffd5b5f546001600160a01b0316801561158f576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b15801561157d575f5ffd5b505afa1580156106c9573d5f5f3e3d5ffd5b505050565b6001600160a01b03811615806115b357506001600160a01b0381166001145b156115dc57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105fb565b6001600160a01b038181165f908152602084905260409020541615611638576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016105fb565b60015f818152602093909352604080842080546001600160a01b0394851680875292862080549590911673ffffffffffffffffffffffffffffffffffffffff199586161790559190935280549091169091179055565b60605f6001600160a01b0384166001148015906116b257506116b0858561184f565b155b156116db57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105fb565b825f03611714576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff81111561172d5761172d6118e3565b604051908082528060200260200182016040528015611756578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061179a57506001600160a01b038216600114155b80156117a557508381105b156117fe57818382815181106117bd576117bd611eca565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806117f68161229f565b915050611778565b6001600160a01b03821660011480159061181757505f81115b1561184357826118286001836122b7565b8151811061183857611838611eca565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061188257506001600160a01b038281165f908152602085905260409020541615155b9392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6118d9606083018486611889565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215611907575f5ffd5b815167ffffffffffffffff81111561191d575f5ffd5b8201601f8101841361192d575f5ffd5b805167ffffffffffffffff811115611947576119476118e3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715611976576119766118e3565b60405281815282820160200186101561198d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61188260208301846119aa565b6001600160a01b03811681146119fe575f5ffd5b50565b8035611a0c816119ea565b919050565b5f5f83601f840112611a21575f5ffd5b50813567ffffffffffffffff811115611a38575f5ffd5b6020830191508360208260051b8501011115611a52575f5ffd5b9250929050565b803560ff81168114611a0c575f5ffd5b5f5f5f5f5f5f5f60a0888a031215611a7f575f5ffd5b8735611a8a816119ea565b9650602088013567ffffffffffffffff811115611aa5575f5ffd5b8801601f81018a13611ab5575f5ffd5b803567ffffffffffffffff811115611acb575f5ffd5b8a6020828401011115611adc575f5ffd5b60209190910196509450611af260408901611a01565b9350606088013567ffffffffffffffff811115611b0d575f5ffd5b611b198a828b01611a11565b9094509250611b2c905060808901611a59565b905092959891949750929550565b5f60208284031215611b4a575f5ffd5b81356001600160e01b031981168114611882575f5ffd5b5f60408284031215611b71575f5ffd5b50919050565b5f5f5f5f5f5f5f60a0888a031215611b8d575f5ffd5b873567ffffffffffffffff811115611ba3575f5ffd5b611baf8a828b01611a11565b909850965050602088013567ffffffffffffffff811115611bce575f5ffd5b611bda8a828b01611b61565b9550506040880135611af2816119ea565b5f5f60408385031215611bfc575f5ffd5b8235611c07816119ea565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b81811015611c575783516001600160a01b0316835260209384019390920191600101611c30565b505080925050506001600160a01b03831660208301529392505050565b5f5f5f5f5f60808688031215611c88575f5ffd5b853567ffffffffffffffff811115611c9e575f5ffd5b611caa88828901611b61565b9550506020860135611cbb816119ea565b9350604086013567ffffffffffffffff811115611cd6575f5ffd5b611ce288828901611a11565b9094509250611cf5905060608701611a59565b90509295509295909350565b6001600160f81b03198816815260e060208201525f611d2360e08301896119aa565b8281036040840152611d3581896119aa565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611d8a578351835260209384019390920191600101611d6c565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f5f5f5f5f60e08c8e031215611db5575f5ffd5b8b3567ffffffffffffffff811115611dcb575f5ffd5b611dd78e828f01611a11565b909c509a505060208c013567ffffffffffffffff811115611df6575f5ffd5b611e028e828f01611a11565b909a5098505060408c013567ffffffffffffffff811115611e21575f5ffd5b611e2d8e828f01611b61565b97505060608c013567ffffffffffffffff811115611e49575f5ffd5b611e558e828f01611a11565b9097509550611e68905060808d01611a01565b935060a08c013567ffffffffffffffff811115611e83575f5ffd5b611e8f8e828f01611a11565b9094509250611ea2905060c08d01611a59565b90509295989b509295989b9093969950565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112611ef2575f5ffd5b9190910192915050565b5f60208284031215611f0c575f5ffd5b8135611882816119ea565b5f5f8335601e19843603018112611f2c575f5ffd5b83018035915067ffffffffffffffff821115611f46575f5ffd5b602001915036819003821315611a52575f5ffd5b8183526020830192505f815f5b84811015611f98578135611f7a816119ea565b6001600160a01b031686526020958601959190910190600101611f67565b5093949350505050565b6001600160a01b038816815260a060208201525f611fc460a08301888a611889565b6001600160a01b03871660408401528281036060840152611fe6818688611f5a565b91505060ff8316608083015298975050505050505050565b6001600160a01b0383168152604060208201525f61201f60408301846119aa565b949350505050565b5f8135612033816119ea565b6001600160a01b03168352602082013536839003601e19018112612055575f5ffd5b820160208101903567ffffffffffffffff811115612071575f5ffd5b80360382131561207f575f5ffd5b60406020860152612094604086018284611889565b95945050505050565b5f8383855260208501945060208460051b820101835f5b868110156120fc57838303601f19018852813536879003603e190181126120d9575f5ffd5b6120e584888301612027565b6020998a01999094509290920191506001016120b4565b50909695505050505050565b60a081525f61211b60a08301898b61209d565b828103602084015261212d8189612027565b90506001600160a01b03871660408401528281036060840152611fe6818688611f5a565b60e081525f61216460e083018d8f61209d565b8281036020840152612177818c8e61209d565b9050828103604084015261218b818b612027565b905082810360608401526121a081898b61209d565b90506001600160a01b038716608084015282810360a08401526121c4818688611f5a565b91505060ff831660c08301529c9b505050505050505050505050565b60ff84168152604060208201525f612094604083018486611f5a565b5f6020828403121561220c575f5ffd5b81518015158114611882575f5ffd5b602081525f61201f602083018486611889565b5f5f8585111561223c575f5ffd5b83861115612248575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015612284576001600160e01b0319808560040360031b1b82161691505b5092915050565b634e487b7160e01b5f52601160045260245ffd5b5f600182016122b0576122b061228b565b5060010190565b81810381811115610cd157610cd161228b56fea164736f6c634300081b000a

Deployed Bytecode

0x6080604052600436106100ca575f3560e01c8063837b892e116100735780639e2533ed1161004d5780639e2533ed14610425578063d6fe71f114610444578063ea5f61d014610463576100d1565b8063837b892e146103b357806384b0196e146103df57806385a924cc14610406576100d1565b806355470cf1116100a457806355470cf1146103495780635faac46b146103685780637b10399914610395576100d1565b806301fe9ff2146102455780630a664dba14610266578063481ddd2314610297576100d1565b366100d157005b5f3660605f6101077f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b90506001600160a01b038116610128576101218484610482565b9150610239565b6040517fd68f60250000000000000000000000000000000000000000000000000000000081525f906001600160a01b0383169063d68f6025906101759033903490869036906004016118b1565b5f604051808303815f875af1158015610190573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101b791908101906118f7565b90506101c38585610482565b92506040517f173bf7da0000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063173bf7da9061020a9084906004016119d8565b5f604051808303815f87803b158015610221575f5ffd5b505af1158015610233573d5f5f3e3d5ffd5b50505050505b50915050805190602001f35b348015610250575f5ffd5b5061026461025f366004611a69565b6106b2565b005b348015610271575f5ffd5b5061027a6106d2565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a2575f5ffd5b506103216102b1366004611b3a565b6001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260209081526040918290208251808401909352546001600160a01b038116808452600160a01b90910460f81b6001600160f81b031916929091018290529091565b604080516001600160f81b031990931683526001600160a01b0390911660208301520161028e565b348015610354575f5ffd5b50610264610363366004611b77565b610709565b348015610373575f5ffd5b50610387610382366004611beb565b6107d2565b60405161028e929190611c15565b3480156103a0575f5ffd5b505f5461027a906001600160a01b031681565b3480156103be575f5ffd5b506103d26103cd366004611c74565b61080b565b60405161028e91906119d8565b3480156103ea575f5ffd5b506103f36108a0565b60405161028e9796959493929190611d01565b348015610411575f5ffd5b506103d2610420366004611b77565b610948565b348015610430575f5ffd5b506103d261043f366004611d9b565b6109d1565b34801561044f575f5ffd5b5061026461045e366004611d9b565b610a66565b34801561046e575f5ffd5b5061038761047d366004611beb565b610c92565b5f80356001600160e01b03191681527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260408120805460609291906001600160a01b03811690600160a01b900460f81b8115610616576104e981607f60f91b610cc0565b1561055657816001600160a01b03166105028888610cd7565b60405161050f9190611eb4565b5f60405180830381855afa9150503d805f8114610547576040519150601f19603f3d011682016040523d82523d5f602084013e61054c565b606091505b5095509350610604565b610560815f610cc0565b156105c157816001600160a01b03163461057a8989610cd7565b6040516105879190611eb4565b5f6040518083038185875af1925050503d805f8114610547576040519150601f19603f3d011682016040523d82523d5f602084013e61054c565b6040517fb96fcfe40000000000000000000000000000000000000000000000000000000081526001600160f81b0319821660048201526024015b60405180910390fd5b8361061157845160208601fd5b6106a8565b5f3560e01c63150b7a02811463f23a6e61821463bc197c81831417171561065557600194506040519550600486528060e01b6020870152602486016040525b6001600160e01b03195f3516856106a5576040517f08c63e270000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105fb565b50505b5050505092915050565b6106be84848484610d0c565b6106c9878787610deb565b50505050505050565b5f6107047f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b905090565b61071584848484610d0c565b5f5b868110156107935761078b88888381811061073457610734611eca565b90506020028101906107469190611ede565b610754906020810190611efc565b89898481811061076657610766611eca565b90506020028101906107789190611ede565b610786906020810190611f17565b610deb565b600101610717565b505f6107a26020870187611efc565b6001600160a01b0316146106c9576106c96107c06020870187611efc565b6107cd6020880188611f17565b610f0b565b60605f6108007f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0085856110ca565b909590945092505050565b606030806301fe9ff261082160208a018a611efc565b61082e60208b018b611f17565b8a8a8a8a6040516024016108489796959493929190611fa2565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610886929190611ffe565b604051602081830303815290604052905095945050505050565b7f0f000000000000000000000000000000000000000000000000000000000000006060805f808083610936604080518082018252600e81527f4e65787573426f6f7473747261700000000000000000000000000000000000006020808301919091528251808401909352600583527f312e302e300000000000000000000000000000000000000000000000000000009083015291565b97989097965046955030945091925090565b606030306001600160a01b03166355470cf18a8a8a8a8a8a8a6040516024016109779796959493929190612108565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506040516020016109b5929190611ffe565b6040516020818303038152906040529050979650505050505050565b606030306001600160a01b031663d6fe71f18e8e8e8e8e8e8e8e8e8e8e604051602401610a089b9a99989796959493929190612151565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050604051602001610a46929190611ffe565b60405160208183030381529060405290509b9a5050505050505050505050565b610a7284848484610d0c565b5f5b8a811015610acb57610ac38c8c83818110610a9157610a91611eca565b9050602002810190610aa39190611ede565b610ab1906020810190611efc565b8d8d8481811061076657610766611eca565b600101610a74565b505f5b88811015610b8b575f8a8a83818110610ae957610ae9611eca565b9050602002810190610afb9190611ede565b610b09906020810190611efc565b6001600160a01b031614610b8357610b838a8a83818110610b2c57610b2c611eca565b9050602002810190610b3e9190611ede565b610b4c906020810190611efc565b8b8b84818110610b5e57610b5e611eca565b9050602002810190610b709190611ede565b610b7e906020810190611f17565b6110e4565b600101610ace565b505f610b9a6020890189611efc565b6001600160a01b031614610bc557610bc5610bb86020890189611efc565b6107cd60208a018a611f17565b5f5b85811015610c84575f878783818110610be257610be2611eca565b9050602002810190610bf49190611ede565b610c02906020810190611efc565b6001600160a01b031614610c7c57610c7c878783818110610c2557610c25611eca565b9050602002810190610c379190611ede565b610c45906020810190611efc565b888884818110610c5757610c57611eca565b9050602002810190610c699190611ede565b610c77906020810190611f17565b6111a2565b600101610bc7565b505050505050505050505050565b60605f6108007f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0185856110ca565b6001600160f81b0319828116908216145b92915050565b6060604080513681016020019091529050601436018152365f602083013760408051601481019091523360601b905292915050565b5f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03861690811790915515610db2576040517ff05c04e10000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f05c04e190610d84908490879087906004016121e0565b5f604051808303815f87803b158015610d9b575f5ffd5b505af1158015610dad573d5f5f3e3d5ffd5b505050505b6040516001600160a01b038516907ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf32905f90a250505050565b826001610df8828261150d565b60405163ecd0596160e01b8152600160048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610e3b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5f91906121fc565b610e7f576040516369c9a24560e11b8152600160048201526024016105fb565b610ea97f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0086611594565b6040516306d61fe760e41b81526001600160a01b03861690636d61fe7090610ed7908790879060040161221b565b5f604051808303815f87803b158015610eee575f5ffd5b505af1158015610f00573d5f5f3e3d5ffd5b505050505050505050565b826004610f18828261150d565b60405163ecd0596160e01b81526004808201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015610f5a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f7e91906121fc565b610f9d576040516369c9a24560e11b81526004818101526024016105fb565b5f610fcf7f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03546001600160a01b031690565b9050806001600160a01b0381161561101f576040517f741cbe030000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016105fb565b507f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f03805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0388161790556040516306d61fe760e41b81526001600160a01b03871690636d61fe7090611095908890889060040161221b565b5f604051808303815f87803b1580156110ac575f5ffd5b505af11580156110be573d5f5f3e3d5ffd5b50505050505050505050565b60605f6110d885858561168e565b90969095509350505050565b8260026110f1828261150d565b60405163ecd0596160e01b8152600260048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa158015611134573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061115891906121fc565b611178576040516369c9a24560e11b8152600260048201526024016105fb565b610ea97f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0186611594565b8260036111af828261150d565b60405163ecd0596160e01b8152600360048201526001600160a01b0386169063ecd0596190602401602060405180830381865afa1580156111f2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061121691906121fc565b611236576040516369c9a24560e11b8152600360048201526024016105fb565b5f611244600482868861222e565b61124d91612255565b90505f8585600481811061126357611263611eca565b9050013560f81c60f81b905061127c815f60f81b610cc0565b80611290575061129081607f60f91b610cc0565b6112c6576040517f867a1dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112d4866005818a61222e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509293505050506001600160e01b031983166306d61fe760e41b148061135257506001600160e01b031983167f8a91b0e300000000000000000000000000000000000000000000000000000000145b8061136557506001600160e01b03198316155b1561139c576040517fc001660b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160e01b031983165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f02602052604090205483906001600160a01b031615611423576040517fa56a04dd0000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024016105fb565b506040805180820182526001600160a01b038a81168083526001600160f81b0319861660208085019182526001600160e01b031989165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0290915285902093518454915160f81c600160a01b027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169316929092179190911790915590516306d61fe760e41b8152636d61fe70906114e49084906004016119d8565b5f604051808303815f87803b1580156114fb575f5ffd5b505af1158015610c84573d5f5f3e3d5ffd5b5f546001600160a01b0316801561158f576040517f96fb72170000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906396fb7217906044015f6040518083038186803b15801561157d575f5ffd5b505afa1580156106c9573d5f5f3e3d5ffd5b505050565b6001600160a01b03811615806115b357506001600160a01b0381166001145b156115dc57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105fb565b6001600160a01b038181165f908152602084905260409020541615611638576040517f40d3d1a40000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016105fb565b60015f818152602093909352604080842080546001600160a01b0394851680875292862080549590911673ffffffffffffffffffffffffffffffffffffffff199586161790559190935280549091169091179055565b60605f6001600160a01b0384166001148015906116b257506116b0858561184f565b155b156116db57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105fb565b825f03611714576040517ff725081700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff81111561172d5761172d6118e3565b604051908082528060200260200182016040528015611756578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b0382161580159061179a57506001600160a01b038216600114155b80156117a557508381105b156117fe57818382815181106117bd576117bd611eca565b6001600160a01b039283166020918202929092018101919091529281165f9081529287905260409092205490911690806117f68161229f565b915050611778565b6001600160a01b03821660011480159061181757505f81115b1561184357826118286001836122b7565b8151811061183857611838611eca565b602002602001015191505b80835250935093915050565b5f60016001600160a01b0383161480159061188257506001600160a01b038281165f908152602085905260409020541615155b9392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385168152836020820152606060408201525f6118d9606083018486611889565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215611907575f5ffd5b815167ffffffffffffffff81111561191d575f5ffd5b8201601f8101841361192d575f5ffd5b805167ffffffffffffffff811115611947576119476118e3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715611976576119766118e3565b60405281815282820160200186101561198d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61188260208301846119aa565b6001600160a01b03811681146119fe575f5ffd5b50565b8035611a0c816119ea565b919050565b5f5f83601f840112611a21575f5ffd5b50813567ffffffffffffffff811115611a38575f5ffd5b6020830191508360208260051b8501011115611a52575f5ffd5b9250929050565b803560ff81168114611a0c575f5ffd5b5f5f5f5f5f5f5f60a0888a031215611a7f575f5ffd5b8735611a8a816119ea565b9650602088013567ffffffffffffffff811115611aa5575f5ffd5b8801601f81018a13611ab5575f5ffd5b803567ffffffffffffffff811115611acb575f5ffd5b8a6020828401011115611adc575f5ffd5b60209190910196509450611af260408901611a01565b9350606088013567ffffffffffffffff811115611b0d575f5ffd5b611b198a828b01611a11565b9094509250611b2c905060808901611a59565b905092959891949750929550565b5f60208284031215611b4a575f5ffd5b81356001600160e01b031981168114611882575f5ffd5b5f60408284031215611b71575f5ffd5b50919050565b5f5f5f5f5f5f5f60a0888a031215611b8d575f5ffd5b873567ffffffffffffffff811115611ba3575f5ffd5b611baf8a828b01611a11565b909850965050602088013567ffffffffffffffff811115611bce575f5ffd5b611bda8a828b01611b61565b9550506040880135611af2816119ea565b5f5f60408385031215611bfc575f5ffd5b8235611c07816119ea565b946020939093013593505050565b604080825283519082018190525f9060208501906060840190835b81811015611c575783516001600160a01b0316835260209384019390920191600101611c30565b505080925050506001600160a01b03831660208301529392505050565b5f5f5f5f5f60808688031215611c88575f5ffd5b853567ffffffffffffffff811115611c9e575f5ffd5b611caa88828901611b61565b9550506020860135611cbb816119ea565b9350604086013567ffffffffffffffff811115611cd6575f5ffd5b611ce288828901611a11565b9094509250611cf5905060608701611a59565b90509295509295909350565b6001600160f81b03198816815260e060208201525f611d2360e08301896119aa565b8281036040840152611d3581896119aa565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611d8a578351835260209384019390920191600101611d6c565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f5f5f5f5f60e08c8e031215611db5575f5ffd5b8b3567ffffffffffffffff811115611dcb575f5ffd5b611dd78e828f01611a11565b909c509a505060208c013567ffffffffffffffff811115611df6575f5ffd5b611e028e828f01611a11565b909a5098505060408c013567ffffffffffffffff811115611e21575f5ffd5b611e2d8e828f01611b61565b97505060608c013567ffffffffffffffff811115611e49575f5ffd5b611e558e828f01611a11565b9097509550611e68905060808d01611a01565b935060a08c013567ffffffffffffffff811115611e83575f5ffd5b611e8f8e828f01611a11565b9094509250611ea2905060c08d01611a59565b90509295989b509295989b9093969950565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e19833603018112611ef2575f5ffd5b9190910192915050565b5f60208284031215611f0c575f5ffd5b8135611882816119ea565b5f5f8335601e19843603018112611f2c575f5ffd5b83018035915067ffffffffffffffff821115611f46575f5ffd5b602001915036819003821315611a52575f5ffd5b8183526020830192505f815f5b84811015611f98578135611f7a816119ea565b6001600160a01b031686526020958601959190910190600101611f67565b5093949350505050565b6001600160a01b038816815260a060208201525f611fc460a08301888a611889565b6001600160a01b03871660408401528281036060840152611fe6818688611f5a565b91505060ff8316608083015298975050505050505050565b6001600160a01b0383168152604060208201525f61201f60408301846119aa565b949350505050565b5f8135612033816119ea565b6001600160a01b03168352602082013536839003601e19018112612055575f5ffd5b820160208101903567ffffffffffffffff811115612071575f5ffd5b80360382131561207f575f5ffd5b60406020860152612094604086018284611889565b95945050505050565b5f8383855260208501945060208460051b820101835f5b868110156120fc57838303601f19018852813536879003603e190181126120d9575f5ffd5b6120e584888301612027565b6020998a01999094509290920191506001016120b4565b50909695505050505050565b60a081525f61211b60a08301898b61209d565b828103602084015261212d8189612027565b90506001600160a01b03871660408401528281036060840152611fe6818688611f5a565b60e081525f61216460e083018d8f61209d565b8281036020840152612177818c8e61209d565b9050828103604084015261218b818b612027565b905082810360608401526121a081898b61209d565b90506001600160a01b038716608084015282810360a08401526121c4818688611f5a565b91505060ff831660c08301529c9b505050505050505050505050565b60ff84168152604060208201525f612094604083018486611f5a565b5f6020828403121561220c575f5ffd5b81518015158114611882575f5ffd5b602081525f61201f602083018486611889565b5f5f8585111561223c575f5ffd5b83861115612248575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015612284576001600160e01b0319808560040360031b1b82161691505b5092915050565b634e487b7160e01b5f52601160045260245ffd5b5f600182016122b0576122b061228b565b5060010190565b81810381811115610cd157610cd161228b56fea164736f6c634300081b000a

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.