ETH Price: $3,009.88 (+1.70%)

Contract

0x0000003eDf18913c01cBc482C978bBD3D6E8ffA3

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
65247462025-07-23 10:45:57184 days ago1753267557  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NexusBootstrap

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 777 runs

Other Settings:
cancun EvmVersion
// 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";
import {
    MODULE_TYPE_VALIDATOR,
    MODULE_TYPE_EXECUTOR,
    MODULE_TYPE_FALLBACK,
    MODULE_TYPE_HOOK
} from "../types/Constants.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;
    }

    struct BootstrapPreValidationHookConfig {
        uint256 hookType;
        address module;
        bytes data;
    }

    struct RegistryConfig {
        IERC7484 registry;
        address[] attesters;
        uint8 threshold;
    }

/// @title NexusBootstrap
/// @notice Manages the installation of modules into Nexus smart accounts using delegatecalls.
contract NexusBootstrap is ModuleManager {

    constructor(address defaultValidator, bytes memory initData) ModuleManager(defaultValidator, initData) {}

    modifier _withInitSentinelLists() {
        _initSentinelLists();
        _;
    }

    /// @notice Initializes the Nexus account with the default validator.
    /// No registry is needed for the default validator.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @dev For gas savings purposes this method does not initialize the registry.
    /// @dev The registry should be initialized via the `setRegistry` function on the Nexus contract later if needed.
    /// @param data The initialization data for the default validator module.
    function initNexusWithDefaultValidator(
        bytes calldata data
    )
        external
        payable
    {
        IModule(_DEFAULT_VALIDATOR).onInstall(data);
    }

    // ================================================
    // ===== DEFAULT VALIDATOR + OTHER MODULES =====
    // ================================================

    /// @notice Initializes the Nexus account with the default validator and other modules and no registry.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @param defaultValidatorInitData The initialization data for the default validator module.
    /// @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 initNexusWithDefaultValidatorAndOtherModulesNoRegistry(
        bytes calldata defaultValidatorInitData,
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        external
        payable
    {
        RegistryConfig memory registryConfig = RegistryConfig({
            registry: IERC7484(address(0)),
            attesters: new address[](0),
            threshold: 0
        });

        _initNexusWithDefaultValidatorAndOtherModules(
            defaultValidatorInitData, 
            validators,
            executors, 
            hook, 
            fallbacks, 
            preValidationHooks, 
            registryConfig
        );
    }

    /// @notice Initializes the Nexus account with the default validator and other modules.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @param defaultValidatorInitData The initialization data for the default validator module.
    /// @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.
    /// @param registryConfig The registry configuration.
    function initNexusWithDefaultValidatorAndOtherModules(
        bytes calldata defaultValidatorInitData,
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks,
        RegistryConfig memory registryConfig
    )
        external
        payable
    {
        _initNexusWithDefaultValidatorAndOtherModules(
            defaultValidatorInitData,
            validators,
            executors, 
            hook, 
            fallbacks, 
            preValidationHooks,
            registryConfig
        );
    }

    function _initNexusWithDefaultValidatorAndOtherModules(
        bytes calldata defaultValidatorInitData,
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks, 
        RegistryConfig memory registryConfig
    )
        internal
        _withInitSentinelLists
    {
        _configureRegistry(registryConfig.registry, registryConfig.attesters, registryConfig.threshold);

        IModule(_DEFAULT_VALIDATOR).onInstall(defaultValidatorInitData);

        for (uint256 i; i < validators.length; i++) {
            if (validators[i].module == address(0)) continue;
            _installValidator(validators[i].module, validators[i].data);
            emit ModuleInstalled(MODULE_TYPE_VALIDATOR, validators[i].module);
        }

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

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

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

        // Initialize pre-validation hooks
        for (uint256 i; i < preValidationHooks.length; i++) {
            if (preValidationHooks[i].module == address(0)) continue;
            _installPreValidationHook(
                preValidationHooks[i].hookType,
                preValidationHooks[i].module,
                preValidationHooks[i].data
            );
            emit ModuleInstalled(preValidationHooks[i].hookType, preValidationHooks[i].module);
        }
    }

    // ================================================
    // ===== SINGLE VALIDATOR =====
    // ================================================

    /// @notice Initializes the Nexus account with a single validator and no registry.
    /// @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 initNexusWithSingleValidatorNoRegistry(
        address validator,
        bytes calldata data
    )
        external
        payable
    {
        RegistryConfig memory registryConfig = RegistryConfig({  
            registry: IERC7484(address(0)),
            attesters: new address[](0),
            threshold: 0
        });
        _initNexusWithSingleValidator(validator, data, registryConfig);
    }

    /// @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.
    /// @param registryConfig The registry configuration.
    function initNexusWithSingleValidator(
        address validator,
        bytes calldata data,
        RegistryConfig memory registryConfig
    )
        external
        payable
    {
        _initNexusWithSingleValidator(validator, data, registryConfig);
    }

    function _initNexusWithSingleValidator(
        address validator,
        bytes calldata data,
        RegistryConfig memory registryConfig
    )
        internal
        _withInitSentinelLists
    {
        _configureRegistry(registryConfig.registry, registryConfig.attesters, registryConfig.threshold);
        _installValidator(validator, data);
        emit ModuleInstalled(MODULE_TYPE_VALIDATOR, validator);
    }

    // ================================================
    // ===== GENERALIZED FLOW =====
    // ================================================

    /// @notice Initializes the Nexus account with multiple modules and no registry.
    /// @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 initNexusNoRegistry(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        external
        payable
    {
        RegistryConfig memory registryConfig = RegistryConfig({
            registry: IERC7484(address(0)),
            attesters: new address[](0),
            threshold: 0
        });

        _initNexus(validators, executors, hook, fallbacks, preValidationHooks, registryConfig);
    }

    /// @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.
    /// @param registryConfig The registry configuration.
    function initNexus(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks,
        RegistryConfig memory registryConfig
    )
        external
        payable
    {
        _initNexus({
            validators: validators,
            executors: executors,
            hook: hook,
            fallbacks: fallbacks,
            preValidationHooks: preValidationHooks,
            registryConfig: registryConfig
        });
    }

    function _initNexus(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks,
        RegistryConfig memory registryConfig
    )
        internal
        _withInitSentinelLists
    {
        _configureRegistry(registryConfig.registry, registryConfig.attesters, registryConfig.threshold);

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

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

        // 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);
            emit ModuleInstalled(MODULE_TYPE_FALLBACK, fallbacks[i].module);
        }

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

        // Initialize pre-validation hooks
        for (uint256 i = 0; i < preValidationHooks.length; i++) {
            if (preValidationHooks[i].module == address(0)) continue;
            _installPreValidationHook(
                preValidationHooks[i].hookType,
                preValidationHooks[i].module,
                preValidationHooks[i].data
            );
            emit ModuleInstalled(preValidationHooks[i].hookType, preValidationHooks[i].module);
        }
    }

    // ================================================
    // ===== SCOPED FLOW =====
    // ================================================

    /// @notice Initializes the Nexus account with a scoped set of modules and no registry.
    /// @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 initNexusScopedNoRegistry(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook
    )
        external
        payable
    {
        RegistryConfig memory registryConfig = RegistryConfig({
            registry: IERC7484(address(0)),
            attesters: new address[](0),
            threshold: 0
        });
        _initNexusScoped(validators, hook, registryConfig);
    }

    /// @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.
    /// @param registryConfig The registry configuration.
    function initNexusScoped(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook,
        RegistryConfig memory registryConfig
    )
        external
        payable
    {
        _initNexusScoped(validators, hook, registryConfig);
    }

    /// @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,
        RegistryConfig memory registryConfig
    )
        internal
        _withInitSentinelLists
    {
        _configureRegistry(registryConfig.registry, registryConfig.attesters, registryConfig.threshold);

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

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

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

    
    // required implementations. Are not used.
    function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable override {
        // do nothing
    }

    function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable override {
        // do nothing
    }

    function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view override returns (bool installed) {
        return false;
    }
}

File 2 of 24 : 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 { IPreValidationHookERC1271, IPreValidationHookERC4337 } from "../interfaces/modules/IPreValidationHook.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 { IModuleManager } from "../interfaces/base/IModuleManager.sol";
import {
    MODULE_TYPE_VALIDATOR,
    MODULE_TYPE_EXECUTOR,
    MODULE_TYPE_FALLBACK,
    MODULE_TYPE_HOOK,
    MODULE_TYPE_PREVALIDATION_HOOK_ERC1271,
    MODULE_TYPE_PREVALIDATION_HOOK_ERC4337,
    MODULE_TYPE_MULTI,
    MODULE_ENABLE_MODE_TYPE_HASH,
    EMERGENCY_UNINSTALL_TYPE_HASH,
    ERC1271_MAGICVALUE
} from "../types/Constants.sol";
import { EIP712 } from "solady/utils/EIP712.sol";
import { ExcessivelySafeCall } from "excessively-safe-call/ExcessivelySafeCall.sol";
import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol";
import { RegistryAdapter } from "./RegistryAdapter.sol";
import { EmergencyUninstall } from "../types/DataTypes.sol";
import { ECDSA } from "solady/utils/ECDSA.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, IModuleManager, RegistryAdapter {
    using SentinelListLib for SentinelListLib.SentinelList;
    using LocalCallDataParserLib for bytes;
    using ExecLib for address;
    using ExcessivelySafeCall for address;
    using ECDSA for bytes32;

    /// @dev The default validator address.
    /// @notice To explicitly initialize the default validator, Nexus.execute(_DEFAULT_VALIDATOR.onInstall(...)) should be called.
    address internal immutable _DEFAULT_VALIDATOR;

    /// @dev initData should block the implementation from being used as a Smart Account
    constructor(address _defaultValidator, bytes memory _initData) {
        if (!IValidator(_defaultValidator).isModuleType(MODULE_TYPE_VALIDATOR)) 
            revert MismatchModuleTypeId(); 
        IValidator(_defaultValidator).onInstall(_initData);
        _DEFAULT_VALIDATOR = _defaultValidator;
    }

    /// @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 function
    receive() external payable { }

    /// @dev Fallback function to manage incoming calls using designated handlers based on the call type.
    /// Hooked manually in the _fallback function
    fallback() external payable {
        _fallback(msg.data);
    }

    /// @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 _initSentinelLists() 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();

        address enableModeSigValidator = _handleValidator(address(bytes20(enableModeSignature[0:20])));
        
        enableModeSignature = enableModeSignature[20:];
        
        if (!_checkEnableModeSignature({
            structHash: _getEnableModeDataHash(module, moduleType, userOpHash, moduleInitData), 
            sig: enableModeSignature,
            validator: enableModeSigValidator
        })) {
            revert EnableModeSigError();
        }
        this.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
    /// - 8 for PreValidationHookERC1271
    /// - 9 for PreValidationHookERC4337
    /// @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 {
        if (!_areSentinelListsInitialized()) {
            _initSentinelLists();
        }
        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_PREVALIDATION_HOOK_ERC1271 || moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) {
            _installPreValidationHook(moduleTypeId, 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
        withHook
        withRegistry(validator, MODULE_TYPE_VALIDATOR) 
    {
        if (!IValidator(validator).isModuleType(MODULE_TYPE_VALIDATOR)) revert MismatchModuleTypeId();
        if (validator == _DEFAULT_VALIDATOR) {
            revert DefaultValidatorAlreadyInstalled();
        }
        _getAccountStorage().validators.push(validator);
        IValidator(validator).onInstall(data);
    }

    /// @dev Uninstalls a validator module.
    /// @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);

        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
        withHook
        withRegistry(executor, MODULE_TYPE_EXECUTOR) 
    {
        if (!IExecutor(executor).isModuleType(MODULE_TYPE_EXECUTOR)) revert MismatchModuleTypeId();
        _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
        withHook
        withRegistry(hook, MODULE_TYPE_HOOK) 
    {
        if (!IHook(hook).isModuleType(MODULE_TYPE_HOOK)) revert MismatchModuleTypeId();
        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 hookType The type of the hook to be uninstalled.
    /// @param data De-initialization data to configure the hook upon uninstallation.
    function _uninstallHook(address hook, uint256 hookType, bytes calldata data) internal virtual {
        if (hookType == MODULE_TYPE_HOOK) {
            _setHook(address(0));
        } else if (hookType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 || hookType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) {
            _uninstallPreValidationHook(hook, hookType, data);
        }
        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
        withHook
        withRegistry(handler, MODULE_TYPE_FALLBACK) 
    {
        if (!IFallback(handler).isModuleType(MODULE_TYPE_FALLBACK)) revert MismatchModuleTypeId();
        // 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:]));
    }

    /// @dev Installs a pre-validation hook module, ensuring no other pre-validation hooks are installed before proceeding.
    /// @param preValidationHookType The type of the pre-validation hook.
    /// @param preValidationHook The address of the pre-validation hook to be installed.
    /// @param data Initialization data to configure the hook upon installation.
    function _installPreValidationHook(
        uint256 preValidationHookType,
        address preValidationHook,
        bytes calldata data
    )
        internal
        virtual
        withHook
        withRegistry(preValidationHook, preValidationHookType)
    {
        if (!IModule(preValidationHook).isModuleType(preValidationHookType)) revert MismatchModuleTypeId();
        address currentPreValidationHook = _getPreValidationHook(preValidationHookType);
        require(currentPreValidationHook == address(0), PrevalidationHookAlreadyInstalled(currentPreValidationHook));
        _setPreValidationHook(preValidationHookType, preValidationHook);
        IModule(preValidationHook).onInstall(data);
    }

    /// @dev Uninstalls a pre-validation hook module
    /// @param preValidationHook The address of the pre-validation hook to be uninstalled.
    /// @param hookType The type of the pre-validation hook.
    /// @param data De-initialization data to configure the hook upon uninstallation.
    function _uninstallPreValidationHook(address preValidationHook, uint256 hookType, bytes calldata data) internal virtual {
        _setPreValidationHook(hookType, address(0));
    }

    /// @dev Sets the current pre-validation hook in the storage to the specified address, based on the hook type.
    /// @param hookType The type of the pre-validation hook.
    /// @param hook The new hook address.
    function _setPreValidationHook(uint256 hookType, address hook) internal virtual {
        if (hookType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271) {
            _getAccountStorage().preValidationHookERC1271 = IPreValidationHookERC1271(hook);
        } else if (hookType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) {
            _getAccountStorage().preValidationHookERC4337 = IPreValidationHookERC4337(hook);
        }
    }

    /// @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]);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*          INSTALL PRE-VALIDATION HOOK                       */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            else if (theType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 || theType == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) {
                _installPreValidationHook(theType, module, initDatas[i]);
            }
        }
    }

    /// @notice Checks if an emergency uninstall signature is valid.
    /// @param data The emergency uninstall data.
    /// @param signature The signature to validate.
    function _checkEmergencyUninstallSignature(EmergencyUninstall calldata data, bytes calldata signature) internal {
        address validator = _handleValidator(address(bytes20(signature[0:20])));
        // Hash the data
        bytes32 hash = _getEmergencyUninstallDataHash(data.hook, data.hookType, data.deInitData, data.nonce);
        // Check if nonce is valid
        require(!_getAccountStorage().nonces[data.nonce], InvalidNonce());
        // Mark nonce as used
        _getAccountStorage().nonces[data.nonce] = true;
        // Check if the signature is valid
        require((IValidator(validator).isValidSignatureWithSender(address(this), hash, signature[20:]) == ERC1271_MAGICVALUE), EmergencyUninstallSigError());
    }

    /// @dev Retrieves the pre-validation hook from the storage based on the hook type.
    /// @param preValidationHookType The type of the pre-validation hook.
    /// @return preValidationHook The address of the pre-validation hook.
    function _getPreValidationHook(uint256 preValidationHookType) internal view returns (address preValidationHook) {
        preValidationHook = preValidationHookType == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271
            ? address(_getAccountStorage().preValidationHookERC1271)
            : address(_getAccountStorage().preValidationHookERC4337);
    }

    /// @dev Calls the pre-validation hook for ERC-1271.
    /// @param hash The hash of the user operation.
    /// @param signature The signature to validate.
    /// @return postHash The updated hash after the pre-validation hook.
    /// @return postSig The updated signature after the pre-validation hook.
    function _withPreValidationHook(bytes32 hash, bytes calldata signature) internal view virtual returns (bytes32 postHash, bytes memory postSig) {
        // Get the pre-validation hook for ERC-1271
        address preValidationHook = _getPreValidationHook(MODULE_TYPE_PREVALIDATION_HOOK_ERC1271);
        // If no pre-validation hook is installed, return the original hash and signature
        if (preValidationHook == address(0)) return (hash, signature);
        // Otherwise, call the pre-validation hook and return the updated hash and signature
        else return IPreValidationHookERC1271(preValidationHook).preValidationHookERC1271(msg.sender, hash, signature);
    }

    /// @dev Calls the pre-validation hook for ERC-4337.
    /// @param hash The hash of the user operation.
    /// @param userOp The user operation data.
    /// @param missingAccountFunds The amount of missing account funds.
    /// @return postHash The updated hash after the pre-validation hook.
    /// @return postSig The updated signature after the pre-validation hook.
    function _withPreValidationHook(
        bytes32 hash,
        PackedUserOperation memory userOp,
        uint256 missingAccountFunds
    )
        internal
        virtual
        returns (bytes32 postHash, bytes memory postSig)
    {
        // Get the pre-validation hook for ERC-4337
        address preValidationHook = _getPreValidationHook(MODULE_TYPE_PREVALIDATION_HOOK_ERC4337);
        // If no pre-validation hook is installed, return the original hash and signature
        if (preValidationHook == address(0)) return (hash, userOp.signature);
        // Otherwise, call the pre-validation hook and return the updated hash and signature
        else return IPreValidationHookERC4337(preValidationHook).preValidationHookERC4337(userOp, missingAccountFunds, hash);
    }

    /// @notice Checks if an enable mode signature is valid.
    /// @param structHash data hash.
    /// @param sig Signature.
    /// @param validator Validator address.
    function _checkEnableModeSignature(
        bytes32 structHash,
        bytes calldata sig,
        address validator
    ) internal view returns (bool) {
        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(validator).isValidSignatureWithSender(address(this), eip712Digest, sig) 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 Builds the emergency uninstall data hash as per eip712
    /// @param hookType Type of the hook (4 for Hook, 8 for ERC-1271 Prevalidation Hook, 9 for ERC-4337 Prevalidation Hook)
    /// @param hook address of the hook being uninstalled
    /// @param data De-initialization data to configure the hook upon uninstallation.
    /// @param nonce Unique nonce for the operation
    /// @return structHash data hash
    function _getEmergencyUninstallDataHash(address hook, uint256 hookType, bytes calldata data, uint256 nonce) internal view returns (bytes32) {
        return _hashTypedData(keccak256(abi.encode(EMERGENCY_UNINSTALL_TYPE_HASH, hook, hookType, keccak256(data), nonce)));
    }

    /// @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 if (moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 || moduleTypeId == MODULE_TYPE_PREVALIDATION_HOOK_ERC4337) {
            return _getPreValidationHook(moduleTypeId) == module;
        } else {
            return false;
        }
    }

    /// @dev Checks if the validator list is already initialized.
    ///      In theory it doesn't 100% mean there is a validator or executor installed.
    ///      Use below functions to check for validators and executors.
    function _areSentinelListsInitialized() internal view virtual returns (bool) {
        // account module storage
        AccountStorage storage ams = _getAccountStorage();
        return ams.validators.alreadyInitialized() && ams.executors.alreadyInitialized();
    }

    /// @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 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);
    }

    /// @dev Checks if the account is an ERC7702 account
    function _amIERC7702() internal view returns (bool res) {
        assembly {
            // use extcodesize as the first cheapest check
            if eq(extcodesize(address()), 23) {
                // use extcodecopy to copy first 3 bytes of this contract and compare with 0xef0100
                extcodecopy(address(), 0, 0, 3)
                res := eq(0xef0100, shr(232, mload(0x00)))
            }
            // if it is not 23, we do not even check the first 3 bytes
        }
    }

    /// @dev Returns the validator address to use
    function _handleValidator(address validator) internal view returns (address) {
        if (validator == address(0)) {
            return _DEFAULT_VALIDATOR;
        } else {
            require(_isValidatorInstalled(validator), ValidatorNotInstalled(validator));
            return validator;
        }
    }

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

        if (handler != address(0)) {
            // hook manually
            address hook = _getHook();
            bytes memory hookData;
            if (hook != address(0)) {
                hookData = IHook(hook).preCheck(msg.sender, msg.value, msg.data);
            }
            //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
            assembly {
                if iszero(success) {
                    revert(add(result, 0x20), mload(result))
                }
            }

            // hook post check
            if (hook != address(0)) {
                IHook(hook).postCheck(hookData);
            }

            // return the result
            assembly {
                return(add(result, 0x20), mload(result))
            }
        }
        
        // If there's no handler, the call can be one of onERCXXXReceived()
        // No need to hook this as no execution is done here
        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))) {
                mstore(0x20, s) // Store `msg.sig`.
                return(0x3c, 0x20) // Return `msg.sig`.
            }
        }
        // if there was no handler and it is not the onERCXXXReceived call, revert
        revert 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);
    }
}

// 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);
}

// 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 24 : 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;

// Module type identifiers for pre-validation hooks
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8;
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9;


// keccak256("ModuleEnableMode(address module,uint256 moduleType,bytes32 userOpHash,bytes initData)")
bytes32 constant MODULE_ENABLE_MODE_TYPE_HASH = 0xf6c866c1cd985ce61f030431e576c0e82887de0643dfa8a2e6efc3463e638ed0;

// keccak256("EmergencyUninstall(address hook,uint256 hookType,bytes deInitData,uint256 nonce)")
bytes32 constant EMERGENCY_UNINSTALL_TYPE_HASH = 0xd3ddfc12654178cc44d4a7b6b969cfdce7ffe6342326ba37825314cffa0fba9c;

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

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

// 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)
        }
    }
}

// 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
        }
    }
}

// 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;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

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

/// @title Nexus - IPreValidationHookERC1271 Interface
/// @notice Defines the interface for ERC-1271 pre-validation hooks
interface IPreValidationHookERC1271 is IModule {
    /// @notice Performs pre-validation checks for isValidSignature
    /// @dev This method is called before the validation of a signature on a validator within isValidSignature
    /// @param sender The original sender of the request
    /// @param hash The hash of signed data
    /// @param data The signature data to validate
    /// @return hookHash The hash after applying the pre-validation hook
    /// @return hookSignature The signature after applying the pre-validation hook
    function preValidationHookERC1271(address sender, bytes32 hash, bytes calldata data) external view returns (bytes32 hookHash, bytes memory hookSignature);
}

/// @title Nexus - IPreValidationHookERC4337 Interface
/// @notice Defines the interface for ERC-4337 pre-validation hooks
interface IPreValidationHookERC4337 is IModule {
    /// @notice Performs pre-validation checks for user operations
    /// @dev This method is called before the validation of a user operation
    /// @param userOp The user operation to be validated
    /// @param missingAccountFunds The amount of funds missing in the account
    /// @param userOpHash The hash of the user operation data
    /// @return hookHash The hash after applying the pre-validation hook
    /// @return hookSignature The signature after applying the pre-validation hook
    function preValidationHookERC4337(
        PackedUserOperation calldata userOp,
        uint256 missingAccountFunds,
        bytes32 userOpHash
    )
        external
        returns (bytes32 hookHash, bytes memory hookSignature);
}

File 10 of 24 : 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 11 of 24 : 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.
}

// 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);
}

// 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);
}

// 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()))
        }
    }

    /**
     * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.
     * @dev code is copied from solady's LibERC7579.sol
     * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146
     *      Credits to Vectorized and the Solady Team
     */
    function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) {
        /// @solidity memory-safe-assembly
        assembly {
            let u := calldataload(executionCalldata.offset)
            let s := add(executionCalldata.offset, u)
            let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)
            executionBatch.offset := add(s, 0x20)
            executionBatch.length := calldataload(s)
            if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {
                mstore(0x00, 0xba597e7e) // `DecodingError()`.
                revert(0x1c, 0x04)
            }
            if executionBatch.length {
                // Perform bounds checks on the decoded `executionBatch`.
                // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.
                for { let i := executionBatch.length } 1 { } {
                    i := sub(i, 1)
                    let p := calldataload(add(executionBatch.offset, shl(5, i)))
                    let c := add(executionBatch.offset, p)
                    let q := calldataload(add(c, 0x40))
                    let o := add(c, q)
                    // forgefmt: disable-next-item
                    if or(shr(64, or(calldataload(o), or(p, q))),
                        or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {
                        mstore(0x00, 0xba597e7e) // `DecodingError()`.
                        revert(0x1c, 0x04)
                    }
                    if iszero(i) { break }
                }
            }
        }
    }   

    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);
    }
}

// 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)
        }
    }
}

// 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 { IModuleManagerEventsAndErrors } from "./IModuleManagerEventsAndErrors.sol";

/// @title Nexus - IModuleManager
/// @notice Interface for managing modules within Smart Accounts, providing methods for installation and removal of modules.
/// @dev Extends the IModuleManagerEventsAndErrors interface to include event and error definitions.
/// @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 IModuleManager is IModuleManagerEventsAndErrors {
    /// @notice Installs a Module of a specific type onto the smart account.
    /// @param moduleTypeId The identifier for the module type.
    /// @param module The address of the module to be installed.
    /// @param initData Initialization data for configuring the module upon installation.
    function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable;

    /// @notice Uninstalls a Module of a specific type from the smart account.
    /// @param moduleTypeId The identifier for the module type being uninstalled.
    /// @param module The address of the module to uninstall.
    /// @param deInitData De-initialization data for configuring the module upon uninstallation.
    function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable;

    /// @notice Checks if a specific module is installed on the smart account.
    /// @param moduleTypeId The module type identifier to check.
    /// @param module The address of the module.
    /// @param additionalContext Additional information that may be required to verify the module's installation.
    /// @return installed True if the module is installed, false otherwise.
    function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool installed);
}

// 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;

    /// @dev `keccak256("EIP712Domain(string name,string version,address verifyingContract)")`.
    /// This is only used in `_hashTypedDataSansChainId`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID =
        0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766;

    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)
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID.
    /// We expect that most contracts will use `_hashTypedData` as the main hash,
    /// and `_hashTypedDataSansChainId` only occasionally for cross-chain workflows.
    /// Thus this is optimized for smaller bytecode size over runtime gas.
    function _hashTypedDataSansChainId(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, address())
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    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)))
        }
    }
}

// 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 19 of 24 : 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;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import { IERC7484 } from "../interfaces/IERC7484.sol";
import { Storage } from "./Storage.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 is Storage {

    /// @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 Returns the configured ERC-7484 registry.
    /// @return The configured registry contract.
    function getRegistry() external view returns (IERC7484) {
        return IERC7484(_getAccountStorage().registry);
    }

    /// @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[] memory attesters, uint8 threshold) internal {
        _getAccountStorage().registry = address(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 = IERC7484(_getAccountStorage().registry);
        if (address(moduleRegistry) != address(0)) {
            // This will revert if attestations or the threshold are not met.
            moduleRegistry.check(module, moduleType);
        }
    }
}

File 21 of 24 : 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;
}

/// @title Emergency Uninstall
/// @notice Struct to encapsulate emergency uninstall data for a hook
struct EmergencyUninstall {
    /// @notice The address of the hook to be uninstalled
    address hook;
    /// @notice The hook type identifier
    uint256 hookType;
    /// @notice Data used to uninstall the hook
    bytes deInitData;
    /// @notice Nonce used to prevent replay attacks
    uint256 nonce;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
///   This is for more safety by default.
///   Use the `tryRecover` variants if you need to get the zero address back
///   upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT directly use signatures as unique identifiers:
/// - The recovery operations do NOT check if a signature is non-malleable.
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
library ECDSA {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The order of the secp256k1 elliptic curve.
    uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;

    /// @dev `N/2 + 1`. Used for checking the malleability of the signature.
    uint256 private constant _HALF_N_PLUS_1 =
        0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The signature is invalid.
    error InvalidSignature();

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

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            } {
                switch mload(signature)
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { continue }
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if returndatasize() { break }
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function recoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            } {
                switch signature.length
                case 64 {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                }
                default { continue }
                mstore(0x00, hash)
                result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if returndatasize() { break }
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   TRY-RECOVER OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // WARNING!
    // These functions will NOT revert upon recovery failure.
    // Instead, they will return the zero address upon recovery failure.
    // It is critical that the returned address is NEVER compared against
    // a zero address (e.g. an uninitialized address variable).

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function tryRecover(bytes32 hash, bytes memory signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {} {
                switch mload(signature)
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                result := mload(xor(0x60, returndatasize()))
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {} {
                switch signature.length
                case 64 {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                }
                default { break }
                mstore(0x00, hash)
                pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                result := mload(xor(0x60, returndatasize()))
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

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

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CANONICAL HASH FUNCTIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // The following functions returns the hash of the signature in it's canonicalized format,
    // which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
    // If `s` is greater than `N / 2` then it will be converted to `N - s`
    // and the `v` value will be flipped.
    // If the signature has an invalid length, or if `v` is invalid,
    // a uniquely corrupt hash will be returned.
    // These functions are useful for "poor-mans-VRF".

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(signature)
            for {} 1 {} {
                mstore(0x00, mload(add(signature, 0x20))) // `r`.
                let s := mload(add(signature, 0x40))
                let v := mload(add(signature, 0x41))
                if eq(l, 64) {
                    v := add(shr(255, s), 27)
                    s := shr(1, shl(1, s))
                }
                if iszero(lt(s, _HALF_N_PLUS_1)) {
                    v := xor(v, 7)
                    s := sub(N, s)
                }
                mstore(0x21, v)
                mstore(0x20, s)
                result := keccak256(0x00, 0x41)
                mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                break
            }

            // If the length is neither 64 nor 65, return a uniquely corrupted hash.
            if iszero(lt(sub(l, 64), 2)) {
                // `bytes4(keccak256("InvalidSignatureLength"))`.
                result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
            }
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHashCalldata(bytes calldata signature)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                mstore(0x00, calldataload(signature.offset)) // `r`.
                let s := calldataload(add(signature.offset, 0x20))
                let v := calldataload(add(signature.offset, 0x21))
                if eq(signature.length, 64) {
                    v := add(shr(255, s), 27)
                    s := shr(1, shl(1, s))
                }
                if iszero(lt(s, _HALF_N_PLUS_1)) {
                    v := xor(v, 7)
                    s := sub(N, s)
                }
                mstore(0x21, v)
                mstore(0x20, s)
                result := keccak256(0x00, 0x41)
                mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                break
            }
            // If the length is neither 64 nor 65, return a uniquely corrupted hash.
            if iszero(lt(sub(signature.length, 64), 2)) {
                calldatacopy(mload(0x40), signature.offset, signature.length)
                // `bytes4(keccak256("InvalidSignatureLength"))`.
                result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2)
            }
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, r) // `r`.
            let v := add(shr(255, vs), 27)
            let s := shr(1, shl(1, vs))
            mstore(0x21, v)
            mstore(0x20, s)
            result := keccak256(0x00, 0x41)
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, r) // `r`.
            if iszero(lt(s, _HALF_N_PLUS_1)) {
                v := xor(v, 7)
                s := sub(N, s)
            }
            mstore(0x21, v)
            mstore(0x20, s)
            result := keccak256(0x00, 0x41)
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

File 23 of 24 : 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 { IPreValidationHookERC1271, IPreValidationHookERC4337 } from "../modules/IPreValidationHook.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 {
        ///< List of validators, initialized upon contract deployment.
        SentinelListLib.SentinelList validators;
        ///< List of executors, similarly initialized.
        SentinelListLib.SentinelList executors;
        ///< Mapping of selectors to their respective fallback handlers.
        mapping(bytes4 => FallbackHandler) fallbacks;
        ///< Current hook module associated with this account.
        IHook hook;
        ///< Mapping of hooks to requested timelocks.
        mapping(address hook => uint256) emergencyUninstallTimelock;
        ///< PreValidation hook for validateUserOp
        IPreValidationHookERC4337 preValidationHookERC4337;
        ///< PreValidation hook for isValidSignature
        IPreValidationHookERC1271 preValidationHookERC1271;
        ///< Mapping of used nonces for replay protection.
        mapping(uint256 => bool) nonces;
        ///< ERC-7484 registry
        address registry;
    }

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

File 24 of 24 : 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 PreValidationHook while another is already installed.
    error PrevalidationHookAlreadyInstalled(address currentPreValidationHook);

    /// @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();

    /// @dev Thrown when unable to validate Emergency Uninstall signature
    error EmergencyUninstallSigError();

    /// @notice Error thrown when an invalid nonce is used
    error InvalidNonce();

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

    /// @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);

    /// @notice Error thrown when the default validator is already installed.
    error DefaultValidatorAlreadyInstalled();
}

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/",
    "lib-prep/=node_modules/prep/src/",
    "composability/=node_modules/@biconomy/composability/contracts/",
    "@ERC4337/=node_modules/@ERC4337/",
    "@biconomy/=node_modules/@biconomy/",
    "@erc7579/=node_modules/@erc7579/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@prb/=node_modules/@prb/",
    "@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/",
    "enumerableset4337/=node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/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/erc7739-validator-base/node_modules/@rhinestone/modulekit/src/",
    "prep/=node_modules/prep/",
    "safe7579/=node_modules/erc7739-validator-base/node_modules/@rhinestone/safe7579/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 777
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"defaultValidator","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CanNotRemoveLastValidator","type":"error"},{"inputs":[],"name":"DefaultValidatorAlreadyInstalled","type":"error"},{"inputs":[],"name":"EmergencyUninstallSigError","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":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"LinkedList_AlreadyInitialized","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":[],"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":"currentPreValidationHook","type":"address"}],"name":"PrevalidationHookAlreadyInstalled","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":[],"name":"getRegistry","outputs":[{"internalType":"contract IERC7484","name":"","type":"address"}],"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[]"},{"components":[{"internalType":"uint256","name":"hookType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapPreValidationHookConfig[]","name":"preValidationHooks","type":"tuple[]"},{"components":[{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"internalType":"struct RegistryConfig","name":"registryConfig","type":"tuple"}],"name":"initNexus","outputs":[],"stateMutability":"payable","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[]"},{"components":[{"internalType":"uint256","name":"hookType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapPreValidationHookConfig[]","name":"preValidationHooks","type":"tuple[]"}],"name":"initNexusNoRegistry","outputs":[],"stateMutability":"payable","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"},{"components":[{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"internalType":"struct RegistryConfig","name":"registryConfig","type":"tuple"}],"name":"initNexusScoped","outputs":[],"stateMutability":"payable","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"}],"name":"initNexusScopedNoRegistry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"initNexusWithDefaultValidator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"defaultValidatorInitData","type":"bytes"},{"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[]"},{"components":[{"internalType":"uint256","name":"hookType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapPreValidationHookConfig[]","name":"preValidationHooks","type":"tuple[]"},{"components":[{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"internalType":"struct RegistryConfig","name":"registryConfig","type":"tuple"}],"name":"initNexusWithDefaultValidatorAndOtherModules","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"defaultValidatorInitData","type":"bytes"},{"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[]"},{"components":[{"internalType":"uint256","name":"hookType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapPreValidationHookConfig[]","name":"preValidationHooks","type":"tuple[]"}],"name":"initNexusWithDefaultValidatorAndOtherModulesNoRegistry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"contract IERC7484","name":"registry","type":"address"},{"internalType":"address[]","name":"attesters","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"internalType":"struct RegistryConfig","name":"registryConfig","type":"tuple"}],"name":"initNexusWithSingleValidator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"initNexusWithSingleValidatorNoRegistry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"installModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"additionalContext","type":"bytes"}],"name":"isModuleInstalled","outputs":[{"internalType":"bool","name":"installed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"deInitData","type":"bytes"}],"name":"uninstallModule","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

610140806040523461023e576134b1803803809161001d82856102aa565b833981019060408183031261023e578051906001600160a01b0382169081830361023e576020810151906001600160401b03821161023e570183601f8201121561023e5780516001600160401b0381116102965760405191610089601f8301601f1916602001846102aa565b81835260208301956020838301011161023e57815f926020809301885e83010152306080524660a05260409360a085516100c387826102aa565b600e815260208101906d04e65787573426f6f7473747261760941b82528751916100ed89846102aa565b60058352602083019164312e322e3160d81b8352519020915190208160c0528060e0528751917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83526020830152878201524660608201523060808201522061010052845163ecd0596160e01b815260016004820152602081602481875afa90811561028c575f91610251575b501561024257823b1561023e576044925f928387519586809581946306d61fe760e41b8352602060048401525180918160248501528484015e8181018301849052601f01601f191681010301925af1801561023457610224575b5061012052516131e390816102ce823960805181505060a05181505060c05181505060e0518150506101005181505061012051818181610429015281816112360152818161197701526121320152f35b5f61022e916102aa565b5f6101d4565b83513d5f823e3d90fd5b5f80fd5b631c4f83bb60e31b5f5260045ffd5b90506020813d602011610284575b8161026c602093836102aa565b8101031261023e5751801515810361023e575f61017a565b3d915061025f565b86513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b038211908210176102965760405256fe60806040526004361015610015575b3661173357005b5f3560e01c80630a664dba1461012f57806310b7fca91461012a578063112d3a7d14610125578063310259841461012057806341bede031461011b578063481ddd2314610116578063544d58601461011157806354ed06d51461010c5780635ab1bd53146101075780635faac46b1461010257806377182ae6146100fd57806384b0196e146100f857806386437876146100f35780638cc8ff1d146100ee5780639517e29f146100e45780639afb7c8d146100e9578063a71763a8146100e45763ea5f61d00361000e57611099565b611003565b61100c565b610f0c565b610e4d565b610d65565b610c42565b610aa5565b610a10565b610890565b6107b4565b6105bc565b6104da565b6103f2565b6103d6565b6101bc565b610142565b5f91031261013e57565b5f80fd5b3461013e575f36600319011261013e5760206001600160a01b035f5160206131775f395f51905f5254166001600160a01b0360405191168152f35b6001600160a01b0381160361013e57565b9181601f8401121561013e5782359167ffffffffffffffff831161013e576020838186019501011161013e57565b604036600319011261013e576004356101d48161017d565b60243567ffffffffffffffff811161013e576101f490369060040161018e565b610247610202939293611195565b60405161020e81610684565b5f81526020810191825260ff6001600160a01b0360408301925f8452610232612a5a565b61023a612adc565b5116925191511691611f39565b6001600160a01b0361026d6001600160a01b035f5160206131775f395f51905f52541690565b16806102b75750906102916102b2925f5160206131375f395f51905f5294836120e1565b60408051600181526001600160a01b03909216602083015290918291820190565b0390a1005b906040519363d68f602560e01b85525f85806102d836343360048501611ed3565b038183875af1948515610367575f9561036c575b50906102f891846120e1565b803b1561013e57604051630b9dfbed60e11b8152925f9184918290849082906103249060048301611f28565b03925af1908115610367575f5160206131375f395f51905f52926102b29261034d575b50610291565b8061035b5f610361936106a0565b80610134565b5f610347565b611216565b6102f89291955061038e903d805f833e61038681836106a0565b810190611e70565b9490916102ec565b606060031982011261013e57600435916024356103b28161017d565b916044359067ffffffffffffffff821161013e576103d29160040161018e565b9091565b3461013e576103e436610396565b5050505060206040515f8152f35b5f602036600319011261013e5760043567ffffffffffffffff811161013e5761041f90369060040161018e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561013e5761047b925f92836040518096819582946306d61fe760e41b845260206004850181815201916111e2565b03925af180156103675761048d575080f35b61049991505f906106a0565b005b9181601f8401121561013e5782359167ffffffffffffffff831161013e576020808501948460051b01011161013e57565b9081604091031261013e5790565b60c036600319011261013e5760043567ffffffffffffffff811161013e5761050690369060040161018e565b60243567ffffffffffffffff811161013e5761052690369060040161049b565b60449391933567ffffffffffffffff811161013e5761054990369060040161049b565b60649291923567ffffffffffffffff811161013e5761056c9036906004016104cc565b9060843567ffffffffffffffff811161013e5761058d90369060040161049b565b94909360a4359867ffffffffffffffff8a1161013e576105b46104999a369060040161049b565b999098611221565b3461013e57602036600319011261013e576004356001600160e01b03198116810361013e576001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f026020526040902060405190604082019082821067ffffffffffffffff831117610670576040918252546001600160a01b03811680845260589190911b6001600160f81b0319166020938401819052825190815292830152819081015b0390f35b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761067057604052565b90601f8019910116810190811067ffffffffffffffff82111761067057604052565b604051906106d16040836106a0565b565b67ffffffffffffffff81116106705760051b60200190565b359060ff8216820361013e57565b91909160608184031261013e576040519061071382610684565b819381356107208161017d565b8352602082013567ffffffffffffffff811161013e5782019080601f8301121561013e57813561074f816106d3565b9261075d60405194856106a0565b81845260208085019260051b82010192831161013e57602001905b82821061079a5750505060408092610795926020860152016106eb565b910152565b6020809183356107a98161017d565b815201910190610778565b60c036600319011261013e5760043567ffffffffffffffff811161013e576107e090369060040161049b565b9060243567ffffffffffffffff811161013e5761080190369060040161049b565b9060443567ffffffffffffffff811161013e576108229036906004016104cc565b60643567ffffffffffffffff811161013e5761084290369060040161049b565b9160843567ffffffffffffffff811161013e5761086390369060040161049b565b95909460a4359867ffffffffffffffff8a1161013e5761088a6104999a36906004016106f9565b98611c6f565b604036600319011261013e5760043567ffffffffffffffff811161013e576108bc90369060040161049b565b9060243567ffffffffffffffff811161013e576108dd9036906004016104cc565b9161093a6108e9611195565b6040516108f581610684565b5f81526020810191825261093461092a60408301925f8452610915612a5a565b61091d612adc565b516001600160a01b031690565b9251915160ff1690565b91611f39565b5f5b8181106109b657836001600160a01b0361095582611c10565b1661095c57005b6102b26109958261099061097d5f5160206131375f395f51905f5295611c10565b61098a6020840184611c1a565b916122f9565b611c10565b60408051600481526001600160a01b03909216602083015290918291820190565b806109e86109ca6109906001948688611be9565b6109e26109d8848789611be9565b6020810190611c1a565b91611ffc565b5f5160206131375f395f51905f52610a07610291610990848789611be9565b0390a10161093c565b3461013e575f36600319011261013e5760206001600160a01b035f5160206131975f395f51905f525416604051908152f35b90602080835192838152019201905f5b818110610a5f5750505090565b82516001600160a01b0316845260209384019390920191600101610a52565b906001600160a01b03610a9e602092959495604085526040850190610a42565b9416910152565b3461013e57604036600319011261013e57600435610ac28161017d565b6024359060016001600160a01b038216141580610c2c575b610c11578115610c025790610aee816111b0565b610b26610b195f946001600160a01b03165f525f5160206131575f395f51905f5260205260405f2090565b546001600160a01b031690565b6001600160a01b0381168015159081610bf6575b5080610bed575b15610b9b57610b8f610b1982610b6c610b9594610b5e89886129e4565b906001600160a01b03169052565b6001600160a01b03165f525f5160206131575f395f51905f5260205260405f2090565b93612a0c565b92610b26565b908360016001600160a01b038416141580610be4575b610bc7575b815261066c60405192839283610a7e565b9150610bde61091d610bd884612a1f565b836129e4565b91610bb6565b50801515610bb1565b50828410610b41565b6001915014155f610b3a565b63f725081760e01b5f5260045ffd5b637c84ecfb60e01b5f526001600160a01b031660045260245ffd5b50610c3d610c39826130b6565b1590565b610ada565b60e036600319011261013e5760043567ffffffffffffffff811161013e57610c6e90369060040161018e565b9060243567ffffffffffffffff811161013e57610c8f90369060040161049b565b9060443567ffffffffffffffff811161013e57610cb090369060040161049b565b9060643567ffffffffffffffff811161013e57610cd19036906004016104cc565b60843567ffffffffffffffff811161013e57610cf190369060040161049b565b93909260a43567ffffffffffffffff811161013e57610d1490369060040161049b565b97909660c4359a67ffffffffffffffff8c1161013e57610d3b6104999c36906004016106f9565b9a611956565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b3461013e575f36600319011261013e57610def6040610dfc815191610d8a81846106a0565b600e83527f4e65787573426f6f74737472617000000000000000000000000000000000000060208401528051610dc082826106a0565b6005815264312e322e3160d81b60208201528151948594600f60f81b865260e0602087015260e0860190610d41565b9184830390850152610d41565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610e34575050500390f35b8251845285945060209384019390920191600101610e26565b60a036600319011261013e5760043567ffffffffffffffff811161013e57610e7990369060040161049b565b60243567ffffffffffffffff811161013e57610e9990369060040161049b565b60449391933567ffffffffffffffff811161013e57610ebc9036906004016104cc565b9060643567ffffffffffffffff811161013e57610edd90369060040161049b565b9290916084359667ffffffffffffffff881161013e57610f0461049998369060040161049b565b979096611550565b606036600319011261013e5760043567ffffffffffffffff811161013e57610f3890369060040161049b565b9060243567ffffffffffffffff811161013e57610f599036906004016104cc565b9160443567ffffffffffffffff811161013e57610f7d610fac9136906004016106f9565b610f85612a5a565b610f8d612adc565b80516001600160a01b0316906109346040602083015192015160ff1690565b5f5b818110610fc757836001600160a01b0361095582611c10565b80610fdb6109ca6109906001948688611be9565b5f5160206131375f395f51905f52610ffa610291610990848789611be9565b0390a101610fae565b61049936610396565b606036600319011261013e576004356110248161017d565b60243567ffffffffffffffff811161013e5761104490369060040161018e565b60449291923567ffffffffffffffff811161013e5761106a6102479136906004016106f9565b611072612a5a565b61107a612adc565b6001600160a01b038151169060ff604060208301519201511691611f39565b3461013e57604036600319011261013e576004356110b68161017d565b6024359060016001600160a01b038216141580611183575b610c11578115610c0257906110e2816111b0565b61110d610b195f946001600160a01b03165f525f5160206131b75f395f51905f5260205260405f2090565b6001600160a01b0381168015159081611177575b508061116e575b15610b9b57610b8f610b198261114561116894610b5e89886129e4565b6001600160a01b03165f525f5160206131b75f395f51905f5260205260405f2090565b9261110d565b50828410611128565b6001915014155f611121565b50611190610c39826130f6565b6110ce565b604051906111a46020836106a0565b5f808352366020840137565b906111ba826106d3565b6111c760405191826106a0565b82815280926111d8601f19916106d3565b0190602036910137565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206112139381815201916111e2565b90565b6040513d5f823e3d90fd5b61122c6108e9611195565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561013e57611281925f92836040518096819582946306d61fe760e41b845260048401611202565b03925af180156103675761153c575b505f5b8281106114d6575050505f5b828110611449575050506112c16112b582611c10565b6001600160a01b031690565b61141f575b505f5b828110611392575050505f5b8281106112e157505050565b806112fd6112b560206112f76001958888611c4d565b01611c10565b1561138d57611342611310828686611c4d565b3561132160206112f7858989611c4d565b9061133a611330858989611c4d565b6040810190611c1a565b929091612895565b5f5160206131375f395f51905f5261135b828686611c4d565b3561136c60206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b016112d5565b611387565b806113a66112b56109906001948787611be9565b1561141a576113d06113bc610990838787611be9565b6113ca6109d8848888611be9565b91612485565b5f5160206131375f395f51905f526114106113ef610990848888611be9565b60408051600381526001600160a01b03909216602083015290918291820190565b0390a15b016112c9565b611414565b6114406109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f6112c6565b8061145d6112b56109906001948787611be9565b156114d157611487611473610990838787611be9565b6114816109d8848888611be9565b916121f0565b5f5160206131375f395f51905f526114c76114a6610990848888611be9565b60408051600281526001600160a01b03909216602083015290918291820190565b0390a15b0161129f565b6114cb565b806114ea6112b56109906001948787611be9565b156115375761150e611500610990838787611be9565b6109e26109d8848888611be9565b5f5160206131375f395f51905f5261152d610291610990848888611be9565b0390a15b01611293565b611531565b8061035b5f61154a936106a0565b5f611290565b90959493956115606108e9611195565b5f5b8181106116f7575050505f5b82811061169f575050505f5b828110611647575050506115906112b582611c10565b61161d575b505f5b8281106115a457505050565b806115ba6112b560206112f76001958888611c4d565b15611618576115cd611310828686611c4d565b5f5160206131375f395f51905f526115e6828686611c4d565b356115f760206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611598565b611612565b61163e6109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f611595565b8061165b6112b56109906001948787611be9565b1561169a576116716113bc610990838787611be9565b5f5160206131375f395f51905f526116906113ef610990848888611be9565b0390a15b0161157a565b611694565b806116b36112b56109906001948787611be9565b156116f2576116c9611473610990838787611be9565b5f5160206131375f395f51905f526116e86114a6610990848888611be9565b0390a15b0161156e565b6116ec565b8061170b6109ca6109906001948688611be9565b5f5160206131375f395f51905f5261172a610291610990848789611be9565b0390a101611562565b5f80356001600160e01b031981168083527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409092205461178c6001600160a01b0382169160581b6001600160f81b03191690565b906001600160a01b0381166117e257505060e01c9063bc197c81821463f23a6e6183141763150b7a028314176117d8576308c63e2760e01b5f526001600160e01b03191660045260245ffd5b506020526020603cf35b5f5160206131775f395f51905f52546001600160a01b03168015159260609290846118ff575b6001600160f81b03198116607f60f91b036118ad57505f8091611829612a2d565b90602082519201905afa9261183c611ef9565b935b156118a557611850575b825160208401f35b803b1561013e57604051630b9dfbed60e11b8152915f91839182908490829061187c9060048301611f28565b03925af1801561036757611891575b80611848565b8061035b5f61189f936106a0565b8161188b565b835160208501fd5b6001600160f81b031981166118e357505f80916118c8612a2d565b906020825192019034905af1926118dd611ef9565b9361183e565b632e5bf3f960e21b5f526001600160f81b03191660045260245ffd5b60405163d68f602560e01b81529093505f818061192136343360048501611ed3565b038183875af1908115610367575f9161193c575b5092611808565b61195091503d805f833e61038681836106a0565b85611935565b909192939495969798999a61196d90610f85612a5a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561013e576119c2925f92836040518096819582946306d61fe760e41b845260048401611202565b03925af1801561036757611bc1575b505f5b828110611b69575050505f5b828110611b11575050506119f66112b582611c10565b611ae7575b505f5b828110611a8f575050505f5b828110611a1657505050565b80611a2c6112b560206112f76001958888611c4d565b15611a8a57611a3f611310828686611c4d565b5f5160206131375f395f51905f52611a58828686611c4d565b35611a6960206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611a0a565b611a84565b80611aa36112b56109906001948787611be9565b15611ae257611ab96113bc610990838787611be9565b5f5160206131375f395f51905f52611ad86113ef610990848888611be9565b0390a15b016119fe565b611adc565b611b086109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f6119fb565b80611b256112b56109906001948787611be9565b15611b6457611b3b611473610990838787611be9565b5f5160206131375f395f51905f52611b5a6114a6610990848888611be9565b0390a15b016119e0565b611b5e565b80611b7d6112b56109906001948787611be9565b15611bbc57611b93611500610990838787611be9565b5f5160206131375f395f51905f52611bb2610291610990848888611be9565b0390a15b016119d4565b611bb6565b8061035b5f611bcf936106a0565b5f6119d1565b634e487b7160e01b5f52603260045260245ffd5b9190811015611c0b5760051b81013590603e198136030182121561013e570190565b611bd5565b356112138161017d565b903590601e198136030182121561013e570180359067ffffffffffffffff821161013e5760200191813603831361013e57565b9190811015611c0b5760051b81013590605e198136030182121561013e570190565b919293969798611c8190610f85612a5a565b5f5b818110611e18575050505f5b828110611dc0575050505f5b828110611d6857505050611cb16112b582611c10565b611d3e575b505f5b828110611cc557505050565b80611cdb6112b560206112f76001958888611c4d565b15611d3957611cee611310828686611c4d565b5f5160206131375f395f51905f52611d07828686611c4d565b35611d1860206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611cb9565b611d33565b611d5f6109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f611cb6565b80611d7c6112b56109906001948787611be9565b15611dbb57611d926113bc610990838787611be9565b5f5160206131375f395f51905f52611db16113ef610990848888611be9565b0390a15b01611c9b565b611db5565b80611dd46112b56109906001948787611be9565b15611e1357611dea611473610990838787611be9565b5f5160206131375f395f51905f52611e096114a6610990848888611be9565b0390a15b01611c8f565b611e0d565b80611e2c6109ca6109906001948688611be9565b5f5160206131375f395f51905f52611e4b610291610990848789611be9565b0390a101611c83565b67ffffffffffffffff811161067057601f01601f191660200190565b60208183031261013e5780519067ffffffffffffffff821161013e570181601f8201121561013e57805190611ea482611e54565b92611eb260405194856106a0565b8284526020838301011161013e57815f9260208093018386015e8301015290565b61121393926001600160a01b03606093168252602082015281604082015201905f6111e2565b3d15611f23573d90611f0a82611e54565b91611f1860405193846106a0565b82523d5f602084013e565b606090565b906020611213928181520190610d41565b6001600160a01b031691826001600160a01b03195f5160206131975f395f51905f525416175f5160206131975f395f51905f525582611f9b575b50507ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf325f80a2565b823b1561013e5760405f91611fd18251948593849363f05c04e160e01b855260ff60048601911681528160208201520190610a42565b038183865af1801561036757611fe8575b80611f73565b8061035b5f611ff6936106a0565b5f611fe2565b91906001600160a01b036120246001600160a01b035f5160206131775f395f51905f52541690565b168061203457506106d1926120e1565b60405163d68f602560e01b81529290915f848061205636343360048501611ed3565b038183875af1938415610367575f946120c1575b506120769293946120e1565b803b1561013e57604051630b9dfbed60e11b8152915f9183918290849082906120a29060048301611f28565b03925af18015610367576120b35750565b8061035b5f6106d1936106a0565b6120769394506120da903d805f833e61038681836106a0565b939261206a565b916120eb83612b4f565b60405163ecd0596160e01b8152600160048201526001600160a01b0384169390602081602481885afa908115610367575f916121a9575b501561219a576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016841461218b5761216190612d64565b823b1561013e576120a2925f92836040518096819582946306d61fe760e41b845260048401611202565b63abc3af7960e01b5f5260045ffd5b631c4f83bb60e31b5f5260045ffd5b6121cb915060203d6020116121d1575b6121c381836106a0565b8101906121d8565b5f612122565b503d6121b9565b9081602091031261013e5751801515810361013e5790565b91906001600160a01b036122186001600160a01b035f5160206131775f395f51905f52541690565b168061222857506106d19261228a565b60405163d68f602560e01b81529290915f848061224a36343360048501611ed3565b038183875af1938415610367575f9461226a575b5061207692939461228a565b612076939450612283903d805f833e61038681836106a0565b939261225e565b9161229483612bca565b60405163ecd0596160e01b8152600260048201526001600160a01b0384169390602081602481885afa908115610367575f916122da575b501561219a5761216190612e9c565b6122f3915060203d6020116121d1576121c381836106a0565b5f6122cb565b91906001600160a01b036123216001600160a01b035f5160206131775f395f51905f52541690565b168061233157506106d192612393565b60405163d68f602560e01b81529290915f848061235336343360048501611ed3565b038183875af1938415610367575f94612373575b50612076929394612393565b61207693945061238c903d805f833e61038681836106a0565b9392612367565b9161239d83612c30565b60405163ecd0596160e01b81526004808201526001600160a01b0384169390602081602481885afa908115610367575f91612442575b501561219a576121619061240e6123fe6001600160a01b035f5160206131775f395f51905f52541690565b6001600160a01b03811615612461565b6001600160a01b03166001600160a01b03195f5160206131775f395f51905f525416175f5160206131775f395f51905f5255565b61245b915060203d6020116121d1576121c381836106a0565b5f6123d3565b156124695750565b6001600160a01b039063741cbe0360e01b5f521660045260245ffd5b91906001600160a01b036124ad6001600160a01b035f5160206131775f395f51905f52541690565b16806124bd57506106d19261251f565b60405163d68f602560e01b81529290915f84806124df36343360048501611ed3565b038183875af1938415610367575f946124ff575b5061207692939461251f565b612076939450612518903d805f833e61038681836106a0565b93926124f3565b909161252a82612c98565b60405163ecd0596160e01b8152600360048201526001600160a01b0383169290602081602481875afa908115610367575f91612781575b501561219a576126c58461268f6125e06125d986806125b76125aa61259c836125966125906127249e8c6127a0565b906127cb565b99612801565b356001600160f81b03191690565b6001600160f81b03191690565b9a6001600160f81b03198c1615801561276a575b6125d490612810565b6127ae565b3691612826565b9661260f6001600160e01b031984166306d61fe760e41b8114908115612759575b8115612750575b501561285c565b6126648361265f610c39826001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0316151590565b612872565b61267e61266f6106c2565b6001600160a01b039096168652565b6001600160f81b0319166020850152565b63ffffffff60e01b165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b8151815460209093015174ff000000000000000000000000000000000000000060589190911c167fffffffffffffffffffffff0000000000000000000000000000000000000000009093166001600160a01b0390911617919091179055565b803b1561013e576040516306d61fe760e41b8152915f9183918290849082906120a29060048301611f28565b9050155f612608565b638a91b0e360e01b81149150612601565b50607f60f91b6001600160f81b03198d16146125cb565b61279a915060203d6020116121d1576121c381836106a0565b5f612561565b9060041161013e5790600490565b909291928360051161013e57831161013e57600501916004190190565b356001600160e01b03198116929190600482106127e6575050565b6001600160e01b031960049290920360031b82901b16169150565b9060041015611c0b5760040190565b1561281757565b63867a1dcf60e01b5f5260045ffd5b92919261283282611e54565b9161284060405193846106a0565b82948184528183011161013e578281602093845f960137010152565b1561286357565b63c001660b60e01b5f5260045ffd5b1561287a5750565b63a56a04dd60e01b5f5263ffffffff60e01b1660045260245ffd5b9291906001600160a01b036128be6001600160a01b035f5160206131775f395f51905f52541690565b16806128ce57506106d193612932565b60405163d68f602560e01b815293909290915f85806128f236343360048501611ed3565b038183885af1948515610367575f95612912575b50612076939495612932565b61207694955061292b903d805f833e61038681836106a0565b9493612906565b92909261293f8185612cfe565b60405163ecd0596160e01b8152600481018290526001600160a01b0385169490602081602481895afa908115610367575f916129a1575b501561219a578161299c61298c61216194612f8c565b6001600160a01b038116156129c0565b612fef565b6129ba915060203d6020116121d1576121c381836106a0565b5f612976565b156129c85750565b6001600160a01b039063c689cd9760e01b5f521660045260245ffd5b8051821015611c0b5760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f198114612a1a5760010190565b6129f8565b5f19810191908211612a1a57565b60405190602036830101604052816014360181525f602036920137604051601481016040523360601b9052565b60015f525f5160206131b75f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13546001600160a01b0316612acd5760015f525f5160206131b75f395f51905f526020526106d160405f2060016001600160a01b0319825416179055565b6329e42f3360e11b5f5260045ffd5b60015f525f5160206131575f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b0316612acd5760015f525f5160206131575f395f51905f526020526106d160405f2060016001600160a01b0319825416179055565b6001600160a01b035f5160206131975f395f51905f5254169081612b71575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260016024820152905f90829060449082905afa801561036757612bb55750565b80612bc15f80936106a0565b80031261013e57565b6001600160a01b035f5160206131975f395f51905f5254169081612bec575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260026024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169081612c52575050565b813b1561013e576040516396fb721760e01b81526001600160a01b039091166004808301919091526024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169081612cba575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260036024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169182612d2157505050565b823b1561013e576040516396fb721760e01b81526001600160a01b039290921660048301526024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b03811680158015612e92575b612e80575f9081525f5160206131575f395f51905f5260205260409020546001600160a01b0316612e655760015f525f5160206131575f395f51905f526020526106d190612e2a612de77ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7610b19565b612e0f835f5160206131575f395f51905f52906001600160a01b03165f5260205260405f2090565b906001600160a01b03166001600160a01b0319825416179055565b60015f525f5160206131575f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7612e0f565b631034f46960e21b5f526001600160a01b031660045260245ffd5b637c84ecfb60e01b5f5260045260245ffd5b5060018114612d77565b6001600160a01b03811680158015612f82575b612e80575f9081525f5160206131b75f395f51905f5260205260409020546001600160a01b0316612e655760015f525f5160206131b75f395f51905f526020526106d190612f47612f1f7fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13610b19565b612e0f835f5160206131b75f395f51905f52906001600160a01b03165f5260205260405f2090565b60015f525f5160206131b75f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13612e0f565b5060018114612eaf565b600803612fc1576001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f06541690565b6001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f05541690565b6008810361305257506001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f065416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0655565b60091461305c5750565b6001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f055416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0555565b6001600160a01b0316806001141590816130ce575090565b90505f525f5160206131575f395f51905f526020526001600160a01b0360405f205416151590565b6001600160a01b03168060011415908161310e575090565b90505f525f5160206131b75f395f51905f526020526001600160a01b0360405f20541615159056fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef1230bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f030bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f080bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01a164736f6c634300081b000a0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000

Deployed Bytecode

0x60806040526004361015610015575b3661173357005b5f3560e01c80630a664dba1461012f57806310b7fca91461012a578063112d3a7d14610125578063310259841461012057806341bede031461011b578063481ddd2314610116578063544d58601461011157806354ed06d51461010c5780635ab1bd53146101075780635faac46b1461010257806377182ae6146100fd57806384b0196e146100f857806386437876146100f35780638cc8ff1d146100ee5780639517e29f146100e45780639afb7c8d146100e9578063a71763a8146100e45763ea5f61d00361000e57611099565b611003565b61100c565b610f0c565b610e4d565b610d65565b610c42565b610aa5565b610a10565b610890565b6107b4565b6105bc565b6104da565b6103f2565b6103d6565b6101bc565b610142565b5f91031261013e57565b5f80fd5b3461013e575f36600319011261013e5760206001600160a01b035f5160206131775f395f51905f5254166001600160a01b0360405191168152f35b6001600160a01b0381160361013e57565b9181601f8401121561013e5782359167ffffffffffffffff831161013e576020838186019501011161013e57565b604036600319011261013e576004356101d48161017d565b60243567ffffffffffffffff811161013e576101f490369060040161018e565b610247610202939293611195565b60405161020e81610684565b5f81526020810191825260ff6001600160a01b0360408301925f8452610232612a5a565b61023a612adc565b5116925191511691611f39565b6001600160a01b0361026d6001600160a01b035f5160206131775f395f51905f52541690565b16806102b75750906102916102b2925f5160206131375f395f51905f5294836120e1565b60408051600181526001600160a01b03909216602083015290918291820190565b0390a1005b906040519363d68f602560e01b85525f85806102d836343360048501611ed3565b038183875af1948515610367575f9561036c575b50906102f891846120e1565b803b1561013e57604051630b9dfbed60e11b8152925f9184918290849082906103249060048301611f28565b03925af1908115610367575f5160206131375f395f51905f52926102b29261034d575b50610291565b8061035b5f610361936106a0565b80610134565b5f610347565b611216565b6102f89291955061038e903d805f833e61038681836106a0565b810190611e70565b9490916102ec565b606060031982011261013e57600435916024356103b28161017d565b916044359067ffffffffffffffff821161013e576103d29160040161018e565b9091565b3461013e576103e436610396565b5050505060206040515f8152f35b5f602036600319011261013e5760043567ffffffffffffffff811161013e5761041f90369060040161018e565b6001600160a01b037f0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe1691823b1561013e5761047b925f92836040518096819582946306d61fe760e41b845260206004850181815201916111e2565b03925af180156103675761048d575080f35b61049991505f906106a0565b005b9181601f8401121561013e5782359167ffffffffffffffff831161013e576020808501948460051b01011161013e57565b9081604091031261013e5790565b60c036600319011261013e5760043567ffffffffffffffff811161013e5761050690369060040161018e565b60243567ffffffffffffffff811161013e5761052690369060040161049b565b60449391933567ffffffffffffffff811161013e5761054990369060040161049b565b60649291923567ffffffffffffffff811161013e5761056c9036906004016104cc565b9060843567ffffffffffffffff811161013e5761058d90369060040161049b565b94909360a4359867ffffffffffffffff8a1161013e576105b46104999a369060040161049b565b999098611221565b3461013e57602036600319011261013e576004356001600160e01b03198116810361013e576001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f026020526040902060405190604082019082821067ffffffffffffffff831117610670576040918252546001600160a01b03811680845260589190911b6001600160f81b0319166020938401819052825190815292830152819081015b0390f35b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761067057604052565b90601f8019910116810190811067ffffffffffffffff82111761067057604052565b604051906106d16040836106a0565b565b67ffffffffffffffff81116106705760051b60200190565b359060ff8216820361013e57565b91909160608184031261013e576040519061071382610684565b819381356107208161017d565b8352602082013567ffffffffffffffff811161013e5782019080601f8301121561013e57813561074f816106d3565b9261075d60405194856106a0565b81845260208085019260051b82010192831161013e57602001905b82821061079a5750505060408092610795926020860152016106eb565b910152565b6020809183356107a98161017d565b815201910190610778565b60c036600319011261013e5760043567ffffffffffffffff811161013e576107e090369060040161049b565b9060243567ffffffffffffffff811161013e5761080190369060040161049b565b9060443567ffffffffffffffff811161013e576108229036906004016104cc565b60643567ffffffffffffffff811161013e5761084290369060040161049b565b9160843567ffffffffffffffff811161013e5761086390369060040161049b565b95909460a4359867ffffffffffffffff8a1161013e5761088a6104999a36906004016106f9565b98611c6f565b604036600319011261013e5760043567ffffffffffffffff811161013e576108bc90369060040161049b565b9060243567ffffffffffffffff811161013e576108dd9036906004016104cc565b9161093a6108e9611195565b6040516108f581610684565b5f81526020810191825261093461092a60408301925f8452610915612a5a565b61091d612adc565b516001600160a01b031690565b9251915160ff1690565b91611f39565b5f5b8181106109b657836001600160a01b0361095582611c10565b1661095c57005b6102b26109958261099061097d5f5160206131375f395f51905f5295611c10565b61098a6020840184611c1a565b916122f9565b611c10565b60408051600481526001600160a01b03909216602083015290918291820190565b806109e86109ca6109906001948688611be9565b6109e26109d8848789611be9565b6020810190611c1a565b91611ffc565b5f5160206131375f395f51905f52610a07610291610990848789611be9565b0390a10161093c565b3461013e575f36600319011261013e5760206001600160a01b035f5160206131975f395f51905f525416604051908152f35b90602080835192838152019201905f5b818110610a5f5750505090565b82516001600160a01b0316845260209384019390920191600101610a52565b906001600160a01b03610a9e602092959495604085526040850190610a42565b9416910152565b3461013e57604036600319011261013e57600435610ac28161017d565b6024359060016001600160a01b038216141580610c2c575b610c11578115610c025790610aee816111b0565b610b26610b195f946001600160a01b03165f525f5160206131575f395f51905f5260205260405f2090565b546001600160a01b031690565b6001600160a01b0381168015159081610bf6575b5080610bed575b15610b9b57610b8f610b1982610b6c610b9594610b5e89886129e4565b906001600160a01b03169052565b6001600160a01b03165f525f5160206131575f395f51905f5260205260405f2090565b93612a0c565b92610b26565b908360016001600160a01b038416141580610be4575b610bc7575b815261066c60405192839283610a7e565b9150610bde61091d610bd884612a1f565b836129e4565b91610bb6565b50801515610bb1565b50828410610b41565b6001915014155f610b3a565b63f725081760e01b5f5260045ffd5b637c84ecfb60e01b5f526001600160a01b031660045260245ffd5b50610c3d610c39826130b6565b1590565b610ada565b60e036600319011261013e5760043567ffffffffffffffff811161013e57610c6e90369060040161018e565b9060243567ffffffffffffffff811161013e57610c8f90369060040161049b565b9060443567ffffffffffffffff811161013e57610cb090369060040161049b565b9060643567ffffffffffffffff811161013e57610cd19036906004016104cc565b60843567ffffffffffffffff811161013e57610cf190369060040161049b565b93909260a43567ffffffffffffffff811161013e57610d1490369060040161049b565b97909660c4359a67ffffffffffffffff8c1161013e57610d3b6104999c36906004016106f9565b9a611956565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b3461013e575f36600319011261013e57610def6040610dfc815191610d8a81846106a0565b600e83527f4e65787573426f6f74737472617000000000000000000000000000000000000060208401528051610dc082826106a0565b6005815264312e322e3160d81b60208201528151948594600f60f81b865260e0602087015260e0860190610d41565b9184830390850152610d41565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610e34575050500390f35b8251845285945060209384019390920191600101610e26565b60a036600319011261013e5760043567ffffffffffffffff811161013e57610e7990369060040161049b565b60243567ffffffffffffffff811161013e57610e9990369060040161049b565b60449391933567ffffffffffffffff811161013e57610ebc9036906004016104cc565b9060643567ffffffffffffffff811161013e57610edd90369060040161049b565b9290916084359667ffffffffffffffff881161013e57610f0461049998369060040161049b565b979096611550565b606036600319011261013e5760043567ffffffffffffffff811161013e57610f3890369060040161049b565b9060243567ffffffffffffffff811161013e57610f599036906004016104cc565b9160443567ffffffffffffffff811161013e57610f7d610fac9136906004016106f9565b610f85612a5a565b610f8d612adc565b80516001600160a01b0316906109346040602083015192015160ff1690565b5f5b818110610fc757836001600160a01b0361095582611c10565b80610fdb6109ca6109906001948688611be9565b5f5160206131375f395f51905f52610ffa610291610990848789611be9565b0390a101610fae565b61049936610396565b606036600319011261013e576004356110248161017d565b60243567ffffffffffffffff811161013e5761104490369060040161018e565b60449291923567ffffffffffffffff811161013e5761106a6102479136906004016106f9565b611072612a5a565b61107a612adc565b6001600160a01b038151169060ff604060208301519201511691611f39565b3461013e57604036600319011261013e576004356110b68161017d565b6024359060016001600160a01b038216141580611183575b610c11578115610c0257906110e2816111b0565b61110d610b195f946001600160a01b03165f525f5160206131b75f395f51905f5260205260405f2090565b6001600160a01b0381168015159081611177575b508061116e575b15610b9b57610b8f610b198261114561116894610b5e89886129e4565b6001600160a01b03165f525f5160206131b75f395f51905f5260205260405f2090565b9261110d565b50828410611128565b6001915014155f611121565b50611190610c39826130f6565b6110ce565b604051906111a46020836106a0565b5f808352366020840137565b906111ba826106d3565b6111c760405191826106a0565b82815280926111d8601f19916106d3565b0190602036910137565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206112139381815201916111e2565b90565b6040513d5f823e3d90fd5b61122c6108e9611195565b6001600160a01b037f0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe1691823b1561013e57611281925f92836040518096819582946306d61fe760e41b845260048401611202565b03925af180156103675761153c575b505f5b8281106114d6575050505f5b828110611449575050506112c16112b582611c10565b6001600160a01b031690565b61141f575b505f5b828110611392575050505f5b8281106112e157505050565b806112fd6112b560206112f76001958888611c4d565b01611c10565b1561138d57611342611310828686611c4d565b3561132160206112f7858989611c4d565b9061133a611330858989611c4d565b6040810190611c1a565b929091612895565b5f5160206131375f395f51905f5261135b828686611c4d565b3561136c60206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b016112d5565b611387565b806113a66112b56109906001948787611be9565b1561141a576113d06113bc610990838787611be9565b6113ca6109d8848888611be9565b91612485565b5f5160206131375f395f51905f526114106113ef610990848888611be9565b60408051600381526001600160a01b03909216602083015290918291820190565b0390a15b016112c9565b611414565b6114406109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f6112c6565b8061145d6112b56109906001948787611be9565b156114d157611487611473610990838787611be9565b6114816109d8848888611be9565b916121f0565b5f5160206131375f395f51905f526114c76114a6610990848888611be9565b60408051600281526001600160a01b03909216602083015290918291820190565b0390a15b0161129f565b6114cb565b806114ea6112b56109906001948787611be9565b156115375761150e611500610990838787611be9565b6109e26109d8848888611be9565b5f5160206131375f395f51905f5261152d610291610990848888611be9565b0390a15b01611293565b611531565b8061035b5f61154a936106a0565b5f611290565b90959493956115606108e9611195565b5f5b8181106116f7575050505f5b82811061169f575050505f5b828110611647575050506115906112b582611c10565b61161d575b505f5b8281106115a457505050565b806115ba6112b560206112f76001958888611c4d565b15611618576115cd611310828686611c4d565b5f5160206131375f395f51905f526115e6828686611c4d565b356115f760206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611598565b611612565b61163e6109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f611595565b8061165b6112b56109906001948787611be9565b1561169a576116716113bc610990838787611be9565b5f5160206131375f395f51905f526116906113ef610990848888611be9565b0390a15b0161157a565b611694565b806116b36112b56109906001948787611be9565b156116f2576116c9611473610990838787611be9565b5f5160206131375f395f51905f526116e86114a6610990848888611be9565b0390a15b0161156e565b6116ec565b8061170b6109ca6109906001948688611be9565b5f5160206131375f395f51905f5261172a610291610990848789611be9565b0390a101611562565b5f80356001600160e01b031981168083527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409092205461178c6001600160a01b0382169160581b6001600160f81b03191690565b906001600160a01b0381166117e257505060e01c9063bc197c81821463f23a6e6183141763150b7a028314176117d8576308c63e2760e01b5f526001600160e01b03191660045260245ffd5b506020526020603cf35b5f5160206131775f395f51905f52546001600160a01b03168015159260609290846118ff575b6001600160f81b03198116607f60f91b036118ad57505f8091611829612a2d565b90602082519201905afa9261183c611ef9565b935b156118a557611850575b825160208401f35b803b1561013e57604051630b9dfbed60e11b8152915f91839182908490829061187c9060048301611f28565b03925af1801561036757611891575b80611848565b8061035b5f61189f936106a0565b8161188b565b835160208501fd5b6001600160f81b031981166118e357505f80916118c8612a2d565b906020825192019034905af1926118dd611ef9565b9361183e565b632e5bf3f960e21b5f526001600160f81b03191660045260245ffd5b60405163d68f602560e01b81529093505f818061192136343360048501611ed3565b038183875af1908115610367575f9161193c575b5092611808565b61195091503d805f833e61038681836106a0565b85611935565b909192939495969798999a61196d90610f85612a5a565b6001600160a01b037f0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe1691823b1561013e576119c2925f92836040518096819582946306d61fe760e41b845260048401611202565b03925af1801561036757611bc1575b505f5b828110611b69575050505f5b828110611b11575050506119f66112b582611c10565b611ae7575b505f5b828110611a8f575050505f5b828110611a1657505050565b80611a2c6112b560206112f76001958888611c4d565b15611a8a57611a3f611310828686611c4d565b5f5160206131375f395f51905f52611a58828686611c4d565b35611a6960206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611a0a565b611a84565b80611aa36112b56109906001948787611be9565b15611ae257611ab96113bc610990838787611be9565b5f5160206131375f395f51905f52611ad86113ef610990848888611be9565b0390a15b016119fe565b611adc565b611b086109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f6119fb565b80611b256112b56109906001948787611be9565b15611b6457611b3b611473610990838787611be9565b5f5160206131375f395f51905f52611b5a6114a6610990848888611be9565b0390a15b016119e0565b611b5e565b80611b7d6112b56109906001948787611be9565b15611bbc57611b93611500610990838787611be9565b5f5160206131375f395f51905f52611bb2610291610990848888611be9565b0390a15b016119d4565b611bb6565b8061035b5f611bcf936106a0565b5f6119d1565b634e487b7160e01b5f52603260045260245ffd5b9190811015611c0b5760051b81013590603e198136030182121561013e570190565b611bd5565b356112138161017d565b903590601e198136030182121561013e570180359067ffffffffffffffff821161013e5760200191813603831361013e57565b9190811015611c0b5760051b81013590605e198136030182121561013e570190565b919293969798611c8190610f85612a5a565b5f5b818110611e18575050505f5b828110611dc0575050505f5b828110611d6857505050611cb16112b582611c10565b611d3e575b505f5b828110611cc557505050565b80611cdb6112b560206112f76001958888611c4d565b15611d3957611cee611310828686611c4d565b5f5160206131375f395f51905f52611d07828686611c4d565b35611d1860206112f7858989611c4d565b604080519283526001600160a01b0391909116602083015290a15b01611cb9565b611d33565b611d5f6109958261099061097d5f5160206131375f395f51905f5295611c10565b0390a15f611cb6565b80611d7c6112b56109906001948787611be9565b15611dbb57611d926113bc610990838787611be9565b5f5160206131375f395f51905f52611db16113ef610990848888611be9565b0390a15b01611c9b565b611db5565b80611dd46112b56109906001948787611be9565b15611e1357611dea611473610990838787611be9565b5f5160206131375f395f51905f52611e096114a6610990848888611be9565b0390a15b01611c8f565b611e0d565b80611e2c6109ca6109906001948688611be9565b5f5160206131375f395f51905f52611e4b610291610990848789611be9565b0390a101611c83565b67ffffffffffffffff811161067057601f01601f191660200190565b60208183031261013e5780519067ffffffffffffffff821161013e570181601f8201121561013e57805190611ea482611e54565b92611eb260405194856106a0565b8284526020838301011161013e57815f9260208093018386015e8301015290565b61121393926001600160a01b03606093168252602082015281604082015201905f6111e2565b3d15611f23573d90611f0a82611e54565b91611f1860405193846106a0565b82523d5f602084013e565b606090565b906020611213928181520190610d41565b6001600160a01b031691826001600160a01b03195f5160206131975f395f51905f525416175f5160206131975f395f51905f525582611f9b575b50507ff98c8404c5b1bfef2e6ba9233c6e88845aedfd36eea8b192725d8c199571cf325f80a2565b823b1561013e5760405f91611fd18251948593849363f05c04e160e01b855260ff60048601911681528160208201520190610a42565b038183865af1801561036757611fe8575b80611f73565b8061035b5f611ff6936106a0565b5f611fe2565b91906001600160a01b036120246001600160a01b035f5160206131775f395f51905f52541690565b168061203457506106d1926120e1565b60405163d68f602560e01b81529290915f848061205636343360048501611ed3565b038183875af1938415610367575f946120c1575b506120769293946120e1565b803b1561013e57604051630b9dfbed60e11b8152915f9183918290849082906120a29060048301611f28565b03925af18015610367576120b35750565b8061035b5f6106d1936106a0565b6120769394506120da903d805f833e61038681836106a0565b939261206a565b916120eb83612b4f565b60405163ecd0596160e01b8152600160048201526001600160a01b0384169390602081602481885afa908115610367575f916121a9575b501561219a576001600160a01b037f0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe16841461218b5761216190612d64565b823b1561013e576120a2925f92836040518096819582946306d61fe760e41b845260048401611202565b63abc3af7960e01b5f5260045ffd5b631c4f83bb60e31b5f5260045ffd5b6121cb915060203d6020116121d1575b6121c381836106a0565b8101906121d8565b5f612122565b503d6121b9565b9081602091031261013e5751801515810361013e5790565b91906001600160a01b036122186001600160a01b035f5160206131775f395f51905f52541690565b168061222857506106d19261228a565b60405163d68f602560e01b81529290915f848061224a36343360048501611ed3565b038183875af1938415610367575f9461226a575b5061207692939461228a565b612076939450612283903d805f833e61038681836106a0565b939261225e565b9161229483612bca565b60405163ecd0596160e01b8152600260048201526001600160a01b0384169390602081602481885afa908115610367575f916122da575b501561219a5761216190612e9c565b6122f3915060203d6020116121d1576121c381836106a0565b5f6122cb565b91906001600160a01b036123216001600160a01b035f5160206131775f395f51905f52541690565b168061233157506106d192612393565b60405163d68f602560e01b81529290915f848061235336343360048501611ed3565b038183875af1938415610367575f94612373575b50612076929394612393565b61207693945061238c903d805f833e61038681836106a0565b9392612367565b9161239d83612c30565b60405163ecd0596160e01b81526004808201526001600160a01b0384169390602081602481885afa908115610367575f91612442575b501561219a576121619061240e6123fe6001600160a01b035f5160206131775f395f51905f52541690565b6001600160a01b03811615612461565b6001600160a01b03166001600160a01b03195f5160206131775f395f51905f525416175f5160206131775f395f51905f5255565b61245b915060203d6020116121d1576121c381836106a0565b5f6123d3565b156124695750565b6001600160a01b039063741cbe0360e01b5f521660045260245ffd5b91906001600160a01b036124ad6001600160a01b035f5160206131775f395f51905f52541690565b16806124bd57506106d19261251f565b60405163d68f602560e01b81529290915f84806124df36343360048501611ed3565b038183875af1938415610367575f946124ff575b5061207692939461251f565b612076939450612518903d805f833e61038681836106a0565b93926124f3565b909161252a82612c98565b60405163ecd0596160e01b8152600360048201526001600160a01b0383169290602081602481875afa908115610367575f91612781575b501561219a576126c58461268f6125e06125d986806125b76125aa61259c836125966125906127249e8c6127a0565b906127cb565b99612801565b356001600160f81b03191690565b6001600160f81b03191690565b9a6001600160f81b03198c1615801561276a575b6125d490612810565b6127ae565b3691612826565b9661260f6001600160e01b031984166306d61fe760e41b8114908115612759575b8115612750575b501561285c565b6126648361265f610c39826001600160e01b0319165f9081527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260409020546001600160a01b0316151590565b612872565b61267e61266f6106c2565b6001600160a01b039096168652565b6001600160f81b0319166020850152565b63ffffffff60e01b165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b8151815460209093015174ff000000000000000000000000000000000000000060589190911c167fffffffffffffffffffffff0000000000000000000000000000000000000000009093166001600160a01b0390911617919091179055565b803b1561013e576040516306d61fe760e41b8152915f9183918290849082906120a29060048301611f28565b9050155f612608565b638a91b0e360e01b81149150612601565b50607f60f91b6001600160f81b03198d16146125cb565b61279a915060203d6020116121d1576121c381836106a0565b5f612561565b9060041161013e5790600490565b909291928360051161013e57831161013e57600501916004190190565b356001600160e01b03198116929190600482106127e6575050565b6001600160e01b031960049290920360031b82901b16169150565b9060041015611c0b5760040190565b1561281757565b63867a1dcf60e01b5f5260045ffd5b92919261283282611e54565b9161284060405193846106a0565b82948184528183011161013e578281602093845f960137010152565b1561286357565b63c001660b60e01b5f5260045ffd5b1561287a5750565b63a56a04dd60e01b5f5263ffffffff60e01b1660045260245ffd5b9291906001600160a01b036128be6001600160a01b035f5160206131775f395f51905f52541690565b16806128ce57506106d193612932565b60405163d68f602560e01b815293909290915f85806128f236343360048501611ed3565b038183885af1948515610367575f95612912575b50612076939495612932565b61207694955061292b903d805f833e61038681836106a0565b9493612906565b92909261293f8185612cfe565b60405163ecd0596160e01b8152600481018290526001600160a01b0385169490602081602481895afa908115610367575f916129a1575b501561219a578161299c61298c61216194612f8c565b6001600160a01b038116156129c0565b612fef565b6129ba915060203d6020116121d1576121c381836106a0565b5f612976565b156129c85750565b6001600160a01b039063c689cd9760e01b5f521660045260245ffd5b8051821015611c0b5760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f198114612a1a5760010190565b6129f8565b5f19810191908211612a1a57565b60405190602036830101604052816014360181525f602036920137604051601481016040523360601b9052565b60015f525f5160206131b75f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13546001600160a01b0316612acd5760015f525f5160206131b75f395f51905f526020526106d160405f2060016001600160a01b0319825416179055565b6329e42f3360e11b5f5260045ffd5b60015f525f5160206131575f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b0316612acd5760015f525f5160206131575f395f51905f526020526106d160405f2060016001600160a01b0319825416179055565b6001600160a01b035f5160206131975f395f51905f5254169081612b71575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260016024820152905f90829060449082905afa801561036757612bb55750565b80612bc15f80936106a0565b80031261013e57565b6001600160a01b035f5160206131975f395f51905f5254169081612bec575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260026024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169081612c52575050565b813b1561013e576040516396fb721760e01b81526001600160a01b039091166004808301919091526024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169081612cba575050565b813b1561013e576040516396fb721760e01b81526001600160a01b03909116600482015260036024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b035f5160206131975f395f51905f5254169182612d2157505050565b823b1561013e576040516396fb721760e01b81526001600160a01b039290921660048301526024820152905f90829060449082905afa801561036757612bb55750565b6001600160a01b03811680158015612e92575b612e80575f9081525f5160206131575f395f51905f5260205260409020546001600160a01b0316612e655760015f525f5160206131575f395f51905f526020526106d190612e2a612de77ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7610b19565b612e0f835f5160206131575f395f51905f52906001600160a01b03165f5260205260405f2090565b906001600160a01b03166001600160a01b0319825416179055565b60015f525f5160206131575f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7612e0f565b631034f46960e21b5f526001600160a01b031660045260245ffd5b637c84ecfb60e01b5f5260045260245ffd5b5060018114612d77565b6001600160a01b03811680158015612f82575b612e80575f9081525f5160206131b75f395f51905f5260205260409020546001600160a01b0316612e655760015f525f5160206131b75f395f51905f526020526106d190612f47612f1f7fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13610b19565b612e0f835f5160206131b75f395f51905f52906001600160a01b03165f5260205260405f2090565b60015f525f5160206131b75f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13612e0f565b5060018114612eaf565b600803612fc1576001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f06541690565b6001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f05541690565b6008810361305257506001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f065416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0655565b60091461305c5750565b6001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f055416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0555565b6001600160a01b0316806001141590816130ce575090565b90505f525f5160206131575f395f51905f526020526001600160a01b0360405f205416151590565b6001600160a01b03168060011415908161310e575090565b90505f525f5160206131b75f395f51905f526020526001600160a01b0360405f20541615159056fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef1230bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f030bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f080bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01a164736f6c634300081b000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000

-----Decoded View---------------
Arg [0] : defaultValidator (address): 0x0000000031ef4155C978d48a8A7d4EDba03b04fE
Arg [1] : initData (bytes): 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000031ef4155c978d48a8a7d4edba03b04fe
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [3] : eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.