ETH Price: $2,821.68 (+2.55%)

Contract

0x000000006f105FED549ee4304269Cc4a6111Fa6e

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
168952752025-11-20 11:28:062 days ago1763638086  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 999 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 "erc7579/interfaces/IERC7579Module.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;
}

/// @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.
    /// @dev Intended to be called by the Nexus with a delegatecall.
    /// @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.
    /// @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. Should not contain the default validator.
    /// @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 preValidationHooks The configuration array for pre-validation hooks.
    function initNexusWithDefaultValidatorAndOtherModules(
        bytes calldata defaultValidatorInitData,
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        public
        payable
        _withInitSentinelLists
    {
        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);
        }
    }

    /// @notice expose this function for backwards compatibility
    function initNexusWithDefaultValidatorAndOtherModulesNoRegistry(
        bytes calldata defaultValidatorInitData,
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        external
        payable
    {
        initNexusWithDefaultValidatorAndOtherModules(
            defaultValidatorInitData, validators, executors, hook, fallbacks, preValidationHooks
        );
    }

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

    /// @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. Should not be the default validator.
    /// @param data The initialization data for the validator module.
    function initNexusWithSingleValidator(
        address validator,
        bytes calldata data
    )
        public
        payable
        _withInitSentinelLists
    {
        _installValidator(validator, data);
        emit ModuleInstalled(MODULE_TYPE_VALIDATOR, validator);
    }

    /// @notice expose this function for backwards compatibility
    function initNexusWithSingleValidatorNoRegistry(address validator, bytes calldata data) external payable {
        initNexusWithSingleValidator(validator, data);
    }

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

    /// @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. Should not contain the default validator.
    /// @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 preValidationHooks The configuration array for pre-validation hooks.
    function initNexus(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        public
        _withInitSentinelLists
    {
        // 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);
        }
    }

    /// @notice expose this function for backwards compatibility
    function initNexusNoRegistry(
        BootstrapConfig[] calldata validators,
        BootstrapConfig[] calldata executors,
        BootstrapConfig calldata hook,
        BootstrapConfig[] calldata fallbacks,
        BootstrapPreValidationHookConfig[] calldata preValidationHooks
    )
        external
        payable
    {
        initNexus(validators, executors, hook, fallbacks, preValidationHooks);
    }

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

    /// @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. Should not contain the default validator.
    /// @param hook The configuration for the hook module.
    function initNexusScoped(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook
    )
        public
        _withInitSentinelLists
    {
        // 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);
        }
    }

    /// @notice expose this function for backwards compatibility
    function initNexusScopedNoRegistry(
        BootstrapConfig[] calldata validators,
        BootstrapConfig calldata hook
    )
        external
        payable
    {
        initNexusScoped(validators, hook);
    }

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

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

    // solhint-disable no-unused-vars
    function isModuleInstalled(
        uint256 moduleTypeId,
        address module,
        bytes calldata additionalContext
    )
        external
        view
        override
        returns (bool installed)
    {
        return false;
    }
    // solhint-enable no-unused-vars
}

File 2 of 18 : 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 {
    IModule,
    IValidator,
    IExecutor,
    IHook,
    IPreValidationHookERC1271,
    IPreValidationHookERC4337,
    IFallback
} from "erc7579/interfaces/IERC7579Module.sol";
import { CallType, CALLTYPE_SINGLE, CALLTYPE_STATIC } from "../../lib/erc-7579/ModeLib.sol";
import { ExecLib } from "../../lib/erc-7579/ExecLib.sol";
import { LocalCallDataParserLib } from "../../lib/nexus/local/LocalCallDataParserLib.sol";
import { IModuleManager } from "../../interfaces/nexus/base/IModuleManager.sol";
// solhint-disable no-unused-import
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_SUCCESS
} from "../../types/Constants.sol";
// solhint-enable no-unused-import
import { EIP712 } from "solady/utils/EIP712.sol";
import { ExcessivelySafeCall } from "excessively-safe-call/ExcessivelySafeCall.sol";
import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol";
import { EmergencyUninstall } from "../../types/DataTypes.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 {
    using SentinelListLib for SentinelListLib.SentinelList;
    using LocalCallDataParserLib for bytes;
    using ExecLib for address;
    using ExcessivelySafeCall for address;

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

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

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

    // 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 the default validator address.
    /// @return The address of the default validator.
    function getDefaultValidator() external view returns (address) {
        return _DEFAULT_VALIDATOR;
    }

    /// @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:];

        bytes32 structHash = _getEnableModeDataHash(module, moduleType, userOpHash, moduleInitData);
        bool isValid = _checkEnableModeSignature(structHash, enableModeSignature, enableModeSigValidator);

        assembly {
            if iszero(isValid) {
                // revert EnableModeSigError()
                mstore(0x00, 0x46fdc333)
                revert(0x1c, 0x04)
            }
        }

        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 (_isPrevalidationHookType(moduleTypeId)) {
            _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 {
        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 {
        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 {
        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 (_isPrevalidationHookType(hookType)) {
            _uninstallPreValidationHook(hookType);
        }
        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 {
        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
    {
        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 hookType The type of the pre-validation hook.
    function _uninstallPreValidationHook(uint256 hookType) 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 (_isPrevalidationHookType(theType)) {
                _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 = _hashTypedData(
            keccak256(
                abi.encode(
                    EMERGENCY_UNINSTALL_TYPE_HASH, data.hook, data.hookType, keccak256(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_SUCCESS),
            EmergencyUninstallSigError()
        );
    }

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

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

    /// @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_SUCCESS;
        } catch {
            return false;
        }
    }

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

    /// @dev Does bytecode optimized check of the module type id being a pre-validation hook type.
    /// @param moduleTypeId The module type id to check.
    /// return True if the module type id is a pre-validation hook type, otherwise false.
    /// If theType == 8: 8 - 8 = 0, and 0 < 2 ✓
    /// If theType == 9: 9 - 8 = 1, and 1 < 2 ✓
    /// If theType < 8 (e.g., 7): 7 - 8 = type(uint256).max (wraps), and type(uint256).max < 2 is false ✓
    /// If theType >= 10: result is >= 2, and fails the check ✓
    function _isPrevalidationHookType(uint256 moduleTypeId) internal pure returns (bool res) {
        assembly {
            res := lt(sub(moduleTypeId, 8), 2)
        }
    }

    /// @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 validator) {
        if (_validator == address(0)) {
            validator = _DEFAULT_VALIDATOR;
        } else {
            if (!_isValidatorInstalled(_validator)) {
                assembly {
                    // revert ValidatorNotInstalled(address)
                    mstore(0x00, 0x6859e01e)
                    mstore(0x20, _validator)
                    revert(0x1c, 0x24)
                }
            }
            validator = _validator;
        }
    }

    /// @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
        pure
        returns (bytes32)
    {
        bytes32 structHash;
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, MODULE_ENABLE_MODE_TYPE_HASH)
            mstore(add(ptr, 0x20), module)
            mstore(add(ptr, 0x40), moduleType)
            mstore(add(ptr, 0x60), userOpHash)

            // Hash initData and store at ptr + 0x80
            // calldatacopy to copy initData to memory, then hash it
            let initDataPtr := add(ptr, 0xa0)
            calldatacopy(initDataPtr, initData.offset, initData.length)
            let initDataHash := keccak256(initDataPtr, initData.length)
            mstore(add(ptr, 0x80), initDataHash)

            // Hash the entire struct
            structHash := keccak256(ptr, 0xa0)
        }
        return structHash;
    }

    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`.
            }
            mstore(0x00, 0x08c63e27)
            mstore(0x20, shl(224, s)) // Left-align bytes4 for ABI encoding
            revert(0x1c, 0x24) // 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.21;

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

uint256 constant VALIDATION_SUCCESS = 0;
uint256 constant VALIDATION_FAILED = 1;

uint256 constant MODULE_TYPE_VALIDATOR = 1;
uint256 constant MODULE_TYPE_EXECUTOR = 2;
uint256 constant MODULE_TYPE_FALLBACK = 3;
uint256 constant MODULE_TYPE_HOOK = 4;
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8;
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9;

interface IModule {
    error AlreadyInitialized(address smartAccount);
    error NotInitialized(address smartAccount);

    /**
     * @dev This function is called by the smart account during installation of the module
     * @param data arbitrary data that may be required on the module during `onInstall`
     * initialization
     *
     * MUST revert on error (i.e. if module is already enabled)
     */
    function onInstall(bytes calldata data) external;

    /**
     * @dev This function is called by the smart account during uninstallation of the module
     * @param data arbitrary data that may be required on the module during `onUninstall`
     * de-initialization
     *
     * MUST revert on error
     */
    function onUninstall(bytes calldata data) external;

    /**
     * @dev Returns boolean value if module is a certain type
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     *
     * MUST return true if the module is of the given type and false otherwise
     */
    function isModuleType(uint256 moduleTypeId) external view returns (bool);

    /**
     * @dev Returns if the module was already initialized for a provided smartaccount
     */
    function isInitialized(address smartAccount) external view returns (bool);
}

interface IValidator is IModule {
    error InvalidTargetAddress(address target);

    /**
     * @dev Validates a transaction on behalf of the account.
     *         This function is intended to be called by the MSA during the ERC-4337 validaton phase
     *         Note: solely relying on bytes32 hash and signature is not suffcient for some
     * validation implementations (i.e. SessionKeys often need access to userOp.calldata)
     * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.
     * The MSA MUST clean up the userOp before sending it to the validator.
     * @param userOpHash The hash of the user operation to be validated
     * @return return value according to ERC-4337
     */
    function validateUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash
    )
        external
        returns (uint256);

    /**
     * Validator can be used for ERC-1271 validation
     */
    function isValidSignatureWithSender(
        address sender,
        bytes32 hash,
        bytes calldata data
    )
        external
        view
        returns (bytes4);
}

interface IExecutor is IModule { }

interface IHook is IModule {
    function preCheck(
        address msgSender,
        uint256 msgValue,
        bytes calldata msgData
    )
        external
        returns (bytes memory hookData);

    function postCheck(bytes calldata hookData) external;
}

interface IFallback is IModule { }

interface IPreValidationHookERC1271 is IModule {
    function preValidationHookERC1271(
        address sender,
        bytes32 hash,
        bytes calldata data
    )
        external
        view
        returns (bytes32 hookHash, bytes memory hookSignature);
}

interface IPreValidationHookERC4337 is IModule {
    function preValidationHookERC4337(
        PackedUserOperation calldata userOp,
        uint256 missingAccountFunds,
        bytes32 userOpHash
    )
        external
        returns (bytes32 hookHash, bytes memory hookSignature);
}

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

// STX Sig types
bytes3 constant SIG_TYPE_MEE_FLOW = 0x177eee;

bytes4 constant SIG_TYPE_SIMPLE = 0x177eee00;
bytes4 constant SIG_TYPE_ON_CHAIN = 0x177eee01;
bytes4 constant SIG_TYPE_ERC20_PERMIT = 0x177eee02;
// ...other sig types: ERC-7683, Permit2, etc

// EIP-1271 constants
bytes4 constant ERC1271_SUCCESS = 0x1626ba7e;
bytes4 constant ERC1271_FAILED = 0xffffffff;

// Node PM constants
bytes4 constant NODE_PM_MODE_USER = 0x170de000; // refund goes to the user
bytes4 constant NODE_PM_MODE_DAPP = 0x170de001; // refund goes to the dApp
bytes4 constant NODE_PM_MODE_KEEP = 0x170de002; // no refund as node sponsored

bytes4 constant NODE_PM_PREMIUM_PERCENT = 0x9ee4ce00; // premium percentage
bytes4 constant NODE_PM_PREMIUM_FIXED = 0x9ee4ce01;

// ERC-4337 validation constants
uint256 constant VALIDATION_SUCCESS = 0;
uint256 constant VALIDATION_FAILED = 1;

// Module type identifiers
uint256 constant MODULE_TYPE_MULTI = 0; // Module type identifier for Multitype install
uint256 constant MODULE_TYPE_VALIDATOR = 1;
uint256 constant MODULE_TYPE_EXECUTOR = 2;
uint256 constant MODULE_TYPE_FALLBACK = 3;
uint256 constant MODULE_TYPE_HOOK = 4;
uint256 constant MODULE_TYPE_STATELESS_VALIDATOR = 7;
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8;
uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9;

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

// ERC-7739 support constants
bytes4 constant SUPPORTS_ERC7739 = 0x77390000;
bytes4 constant SUPPORTS_ERC7739_V1 = 0x77390001;

// Typehashes

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

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

/// @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 "erc7579/interfaces/IERC7579Account.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 {
    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;

    /// @dev `keccak256("EIP712Domain(string name,string version)")`.
    /// This is only used in `_hashTypedDataSansChainIdAndVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT =
        0xb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3;

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId)")`.
    /// This is only used in `_hashTypedDataSansVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT =
        0xc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e;

    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.
    /// Included for the niche use case of cross-chain workflows.
    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.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of cross-chain and multi-verifier workflows.
    function _hashTypedDataSansChainIdAndVerifyingContract(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_AND_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x60)) // 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.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of multi-verifier workflows.
    function _hashTypedDataSansVerifyingContract(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_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, chainid())
            // 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 13 of 18 : PackedUserOperation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

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

File 14 of 18 : 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 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;
}

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

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

import { SentinelListLib } from "sentinellist/SentinelList.sol";
import { IHook, IPreValidationHookERC1271, IPreValidationHookERC4337 } from "erc7579/interfaces/IERC7579Module.sol";
import { CallType } from "../../../lib/erc-7579/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; // keeping this to avoid collisions b/w versions
        ///< Mapping of used 7702 init hashes for replay protection.
        mapping(bytes32 => bool) erc7702InitHashes;
    }

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

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

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

struct Execution {
    address target;
    uint256 value;
    bytes callData;
}

interface IERC7579Account {
    event ModuleInstalled(uint256 moduleTypeId, address module);
    event ModuleUninstalled(uint256 moduleTypeId, address module);

    /**
     * @dev Executes a transaction on behalf of the account.
     *         This function is intended to be called by ERC-4337 EntryPoint.sol
     * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf
     *
     * @dev MSA MUST implement this function signature.
     * If a mode is requested that is not supported by the Account, it MUST revert
     * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
     * @param executionCalldata The encoded execution call data
     */
    function execute(ModeCode mode, bytes calldata executionCalldata) external payable;

    /**
     * @dev Executes a transaction on behalf of the account.
     *         This function is intended to be called by Executor Modules
     * @dev Ensure adequate authorization control: i.e. onlyExecutorModule
     *
     * @dev MSA MUST implement this function signature.
     * If a mode is requested that is not supported by the Account, it MUST revert
     * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
     * @param executionCalldata The encoded execution call data
     */
    function executeFromExecutor(
        ModeCode mode,
        bytes calldata executionCalldata
    )
        external
        payable
        returns (bytes[] memory returnData);

    /**
     * @dev ERC-1271 isValidSignature
     *         This function is intended to be used to validate a smart account signature
     * and may forward the call to a validator module
     *
     * @param hash The hash of the data that is signed
     * @param data The data that is signed
     */
    function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);

    /**
     * @dev installs a Module of a certain type on the smart account
     * @dev Implement Authorization control of your chosing
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     * @param module the module address
     * @param initData arbitrary data that may be required on the module during `onInstall`
     * initialization.
     */
    function installModule(
        uint256 moduleTypeId,
        address module,
        bytes calldata initData
    )
        external
        payable;

    /**
     * @dev uninstalls a Module of a certain type on the smart account
     * @dev Implement Authorization control of your chosing
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     * @param module the module address
     * @param deInitData arbitrary data that may be required on the module during `onUninstall`
     * de-initialization.
     */
    function uninstallModule(
        uint256 moduleTypeId,
        address module,
        bytes calldata deInitData
    )
        external
        payable;

    /**
     * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)
     * @param encodedMode the encoded mode
     */
    function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);

    /**
     * Function to check if the account supports installation of a certain module type Id
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     */
    function supportsModule(uint256 moduleTypeId) external view returns (bool);

    /**
     * Function to check if the account has a certain module installed
     * @param moduleTypeId the module type ID according the ERC-7579 spec
     *      Note: keep in mind that some contracts can be multiple module types at the same time. It
     *            thus may be necessary to query multiple module types
     * @param module the module address
     * @param additionalContext additional context data that the smart account may interpret to
     *                          identifiy conditions under which the module is installed.
     *                          usually this is not necessary, but for some special hooks that
     *                          are stored in mappings, this param might be needed
     */
    function isModuleInstalled(
        uint256 moduleTypeId,
        address module,
        bytes calldata additionalContext
    )
        external
        view
        returns (bool);

    /**
     * @dev Returns the account id of the smart account
     * @return accountImplementationId the account id of the smart account
     * the accountId should be structured like so:
     *        "vendorname.accountname.semver"
     */
    function accountId() external view returns (string memory accountImplementationId);
}

File 17 of 18 : 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/erc-7579/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);

    /// @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 Invalid data is provided for MultiType install flow
    error InvalidInput();

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

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

/**
 * @title ModeLib
 * 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(ModeCode 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
 */
import { Execution } from "../interfaces/IERC7579Account.sol";

// Custom type for improved developer experience
type ModeCode 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);
// @dev Implementing delegatecall is OPTIONAL!
// implement delegatecall with extreme care.
CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);
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(ModeCode 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 encode(
        CallType callType,
        ExecType execType,
        ModeSelector mode,
        ModePayload payload
    )
        internal
        pure
        returns (ModeCode)
    {
        return ModeCode.wrap(
            bytes32(
                abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)
            )
        );
    }

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

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

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

using { eqModeSelector as == } for ModeSelector global;
using { eqCallType 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 eqExecType(ExecType a, ExecType b) pure returns (bool) {
    return ExecType.unwrap(a) == ExecType.unwrap(b);
}

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

Settings
{
  "remappings": [
    "forge-std/=node_modules/forge-std/src/",
    "account-abstraction/=node_modules/account-abstraction/contracts/",
    "solady/=node_modules/solady/src/",
    "sentinellist/=node_modules/@rhinestone/sentinellist/src/",
    "module-bases/=node_modules/@rhinestone/module-bases/src/",
    "erc7739Validator/=node_modules/@erc7579/erc7739-validator-base/src/",
    "EnumerableSet4337/=node_modules/@erc7579/enumerablemap4337/src/",
    "erc7579/=node_modules/@erc7579/implementation/src/",
    "byteslib/=node_modules/solidity-bytes-utils/contracts/",
    "rlp-reader/=node_modules/solidity-rlp/contracts/",
    "murky-trees/=node_modules/murky/src/",
    "solarray/=node_modules/solarray/src/",
    "excessively-safe-call/=node_modules/excessively-safe-call/src/",
    "@ERC4337/=node_modules/@ERC4337/",
    "@erc7579/=node_modules/@erc7579/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@prb/=node_modules/@prb/",
    "@rhinestone/=node_modules/@rhinestone/",
    "@safe-global/=node_modules/@safe-global/",
    "@zerodev/=node_modules/@zerodev/",
    "account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/",
    "ds-test/=node_modules/ds-test/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "solidity-rlp/=node_modules/solidity-rlp/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "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":"DefaultValidatorAlreadyInstalled","type":"error"},{"inputs":[],"name":"EmergencyUninstallSigError","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"FallbackAlreadyInstalledForSelector","type":"error"},{"inputs":[],"name":"FallbackCallTypeInvalid","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":[],"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":[{"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"},{"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":[],"name":"getDefaultValidator","outputs":[{"internalType":"address","name":"","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":[{"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[]"}],"name":"initNexus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"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"}],"name":"initNexusScoped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig[]","name":"validators","type":"tuple[]"},{"components":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BootstrapConfig","name":"hook","type":"tuple"}],"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[]"}],"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"}],"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"}]

610140806040523461023e57612c57803803809161001d82856102aa565b833981019060408183031261023e578051906001600160a01b0382169081830361023e576020810151906001600160401b03821161023e570183601f8201121561023e5780516001600160401b0381116102965760405191610089601f8301601f1916602001846102aa565b81835260208301956020838301011161023e57815f926020809301885e83010152306080524660a05260409360a085516100c387826102aa565b600e815260208101906d04e65787573426f6f7473747261760941b82528751916100ed89846102aa565b600583526020830191640312e332e360dc1b8352519020915190208160c0528060e0528751917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83526020830152878201524660608201523060808201522061010052845163ecd0596160e01b815260016004820152602081602481875afa90811561028c575f91610251575b501561024257823b1561023e576044925f928387519586809581946306d61fe760e41b8352602060048401525180918160248501528484015e8181018301849052601f01601f191681010301925af1801561023457610224575b50610120525161298990816102ce823960805181505060a05181505060c05181505060e05181505061010051815050610120518181816101920152818161053a015281816108d101526119c30152f35b5f61022e916102aa565b5f6101d4565b83513d5f823e3d90fd5b5f80fd5b631c4f83bb60e31b5f5260045ffd5b90506020813d602011610284575b8161026c602093836102aa565b8101031261023e5751801515810361023e575f61017a565b3d915061025f565b86513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b038211908210176102965760405256fe60806040526004361015610015575b3661158d57005b5f3560e01c80630a664dba146101255780630b3dc3541461012057806310b7fca9146100f8578063112d3a7d1461011b578063220911871461010c578063310259841461011657806334ea61a51461011157806341bede031461010c578063481ddd231461010757806354ed06d5146101025780635faac46b146100fd5780636d583e36146100f857806384b0196e146100f357806386437876146100ee5780639517e29f146100e9578063a71763a8146100e9578063a8a33cf2146100e45763ea5f61d00361000e57611374565b61117c565b611173565b610f80565b610daf565b610232565b610bc8565b610aff565b610a41565b61050b565b610994565b61089a565b6103d8565b610173565b610138565b5f91031261013457565b5f80fd5b34610134575f3660031901126101345760206001600160a01b035f51602061293d5f395f51905f5254166001600160a01b0360405191168152f35b34610134575f3660031901126101345760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b6001600160a01b0381160361013457565b9181601f840112156101345782359167ffffffffffffffff8311610134576020838186019501011161013457565b9060406003198301126101345760043561020e816101b6565b916024359067ffffffffffffffff82116101345761022e916004016101c7565b9091565b61023b366101f5565b6102469291926122f9565b61024e612394565b6001600160a01b036102746001600160a01b035f51602061293d5f395f51905f52541690565b16806102be5750906102986102b9925f5160206128fd5f395f51905f52948361197b565b60408051600181526001600160a01b03909216602083015290918291820190565b0390a1005b906040519363d68f602560e01b85525f85806102df36343360048501611848565b038183875af194851561036d575f95610372575b50906102ff918461197b565b803b156101345761032a5f93918492604051958680948193630b9dfbed60e11b83526004830161186e565b03925af190811561036d575f5160206128fd5f395f51905f52926102b992610353575b50610298565b806103615f61036793611484565b8061012a565b5f61034d565b6114d7565b6102ff92919550610394903d805f833e61038c8183611484565b8101906117e5565b9490916102f3565b606060031982011261013457600435916024356103b8816101b6565b916044359067ffffffffffffffff82116101345761022e916004016101c7565b34610134576103e63661039c565b5050505060206040515f8152f35b9181601f840112156101345782359167ffffffffffffffff8311610134576020808501948460051b01011161013457565b908160409103126101345790565b9060c06003198301126101345760043567ffffffffffffffff8111610134578261045f916004016101c7565b9290929160243567ffffffffffffffff81116101345782610482916004016103f4565b9290929160443567ffffffffffffffff811161013457826104a5916004016103f4565b9290929160643567ffffffffffffffff811161013457826104c891600401610425565b9160843567ffffffffffffffff811161013457816104e8916004016103f4565b9290929160a4359067ffffffffffffffff82116101345761022e916004016103f4565b61051436610433565b9890996105289892989793979694966122f9565b610530612394565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561013457610585925f92836040518096819582946306d61fe760e41b8452600484016114c6565b03925af1801561036d57610886575b505f5b82811061081a575050505f5b82811061078d575050506105c56105b98261151d565b6001600160a01b031690565b61072f575b505f5b828110610693575050505f5b8181106105e257005b806105fe6105b960206105f8600195878961155a565b0161151d565b1561068e5761064361061182858761155a565b3561062260206105f885888a61155a565b9061063b61063185888a61155a565b6040810190611527565b92909161216e565b5f5160206128fd5f395f51905f5261065c82858761155a565b3561066d60206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b016105d9565b610688565b806106ac6105b96106a760019487876114f6565b61151d565b1561072a576106e06106c26106a78387876114f6565b6106da6106d08488886114f6565b6020810190611527565b91611d37565b5f5160206128fd5f395f51905f526107206106ff6106a78488886114f6565b60408051600381526001600160a01b03909216602083015290918291820190565b0390a15b016105cd565b610724565b610784610763826106a76107505f5160206128fd5f395f51905f529561151d565b61075d6020840184611527565b91611b9b565b60408051600481526001600160a01b03909216602083015290918291820190565b0390a15f6105ca565b806107a16105b96106a760019487876114f6565b15610815576107cb6107b76106a78387876114f6565b6107c56106d08488886114f6565b91611a9b565b5f5160206128fd5f395f51905f5261080b6107ea6106a78488886114f6565b60408051600281526001600160a01b03909216602083015290918291820190565b0390a15b016105a3565b61080f565b8061082e6105b96106a760019487876114f6565b15610881576108586108446106a78387876114f6565b6108526106d08488886114f6565b9161187f565b5f5160206128fd5f395f51905f526108776102986106a78488886114f6565b0390a15b01610597565b61087b565b806103615f61089493611484565b5f610594565b5f60203660031901126101345760043567ffffffffffffffff8111610134576108c79036906004016101c7565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561013457610923925f92836040518096819582946306d61fe760e41b845260206004850181815201916114a6565b03925af1801561036d57610935575080f35b61094191505f90611484565b005b60406003198201126101345760043567ffffffffffffffff8111610134578161096e916004016103f4565b929092916024359067ffffffffffffffff82116101345761099191600401610425565b90565b34610134576109a236610943565b91906109ac6122f9565b6109b4612394565b5f5b8181106109f757836001600160a01b036109cf8261151d565b166109d657005b6102b9610763826106a76107505f5160206128fd5f395f51905f529561151d565b80610a19610a0b6106a760019486886114f6565b6108526106d08487896114f6565b5f5160206128fd5f395f51905f52610a386102986106a78487896114f6565b0390a1016109b6565b34610134576020366003190112610134576004356001600160e01b03198116810361013457610aa1906001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b60405190604082019082821067ffffffffffffffff831117610afa576040918252546001600160a01b03811680845260589190911b6001600160f81b0319166020938401819052825190815292830152819081015b0390f35b611470565b610b0836610943565b9190610b126122f9565b610b1a612394565b5f5b818110610b3557836001600160a01b036109cf8261151d565b80610b49610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f52610b686102986106a78487896114f6565b0390a101610b1c565b90929192604082016040835281518091526020606084019201905f5b818110610ba9575050506001600160a01b036020919416910152565b82516001600160a01b0316845260209384019390920191600101610b8d565b3461013457604036600319011261013457600435610be5816101b6565b6024359060016001600160a01b038216141580610d75575b610d5a578115610d325790610c11816127d4565b610c49610c3c5f946001600160a01b03165f525f51602061291d5f395f51905f5260205260405f2090565b546001600160a01b031690565b6001600160a01b0381168015159081610d26575b5080610d1d575b15610cbe57610cb2610c3c82610c8f610cb894610c818988612806565b906001600160a01b03169052565b6001600160a01b03165f525f51602061291d5f395f51905f5260205260405f2090565b9361282e565b92610c49565b908360016001600160a01b038416141580610d14575b610cea575b8152610af660405192839283610b71565b9150610d0e610d01610cfb84612841565b83612806565b516001600160a01b031690565b91610cd9565b50801515610cd4565b50828410610c64565b6001915014155f610c5d565b7ff7250817000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c84ecfb60e01b5f526001600160a01b031660045260245ffd5b50610d86610d828261287c565b1590565b610bfd565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610134575f36600319011261013457610e6d6040610e7a815191610dd48184611484565b600e83527f4e65787573426f6f74737472617000000000000000000000000000000000000060208401528051610e0a8282611484565b600581527f312e332e30000000000000000000000000000000000000000000000000000000602082015281519485947f0f00000000000000000000000000000000000000000000000000000000000000865260e0602087015260e0860190610d8b565b9184830390850152610d8b565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610eb2575050500390f35b8251845285945060209384019390920191600101610ea4565b9060a06003198301126101345760043567ffffffffffffffff81116101345782610ef7916004016103f4565b9290929160243567ffffffffffffffff81116101345782610f1a916004016103f4565b9290929160443567ffffffffffffffff81116101345782610f3d91600401610425565b9160643567ffffffffffffffff81116101345781610f5d916004016103f4565b929092916084359067ffffffffffffffff82116101345761022e916004016103f4565b610f8936610ecb565b96610f9b9891989692959394966122f9565b610fa3612394565b5f5b818110611137575050505f5b8281106110df575050505f5b82811061108757505050610fd36105b98261151d565b61105d575b505f5b818110610fe457005b80610ffa6105b960206105f8600195878961155a565b156110585761100d61061182858761155a565b5f5160206128fd5f395f51905f5261102682858761155a565b3561103760206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b01610fdb565b611052565b61107e610763826106a76107505f5160206128fd5f395f51905f529561151d565b0390a15f610fd8565b8061109b6105b96106a760019487876114f6565b156110da576110b16106c26106a78387876114f6565b5f5160206128fd5f395f51905f526110d06106ff6106a78488886114f6565b0390a15b01610fbd565b6110d4565b806110f36105b96106a760019487876114f6565b15611132576111096107b76106a78387876114f6565b5f5160206128fd5f395f51905f526111286107ea6106a78488886114f6565b0390a15b01610fb1565b61112c565b8061114b610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f5261116a6102986106a78487896114f6565b0390a101610fa5565b6109413661039c565b346101345761118a36610ecb565b9661119c9891989692959394966122f9565b6111a4612394565b5f5b818110611338575050505f5b8281106112e0575050505f5b828110611288575050506111d46105b98261151d565b61125e575b505f5b8181106111e557005b806111fb6105b960206105f8600195878961155a565b156112595761120e61061182858761155a565b5f5160206128fd5f395f51905f5261122782858761155a565b3561123860206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b016111dc565b611253565b61127f610763826106a76107505f5160206128fd5f395f51905f529561151d565b0390a15f6111d9565b8061129c6105b96106a760019487876114f6565b156112db576112b26106c26106a78387876114f6565b5f5160206128fd5f395f51905f526112d16106ff6106a78488886114f6565b0390a15b016111be565b6112d5565b806112f46105b96106a760019487876114f6565b156113335761130a6107b76106a78387876114f6565b5f5160206128fd5f395f51905f526113296107ea6106a78488886114f6565b0390a15b016111b2565b61132d565b8061134c610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f5261136b6102986106a78487896114f6565b0390a1016111a6565b3461013457604036600319011261013457600435611391816101b6565b6024359060016001600160a01b03821614158061145e575b610d5a578115610d3257906113bd816127d4565b6113e8610c3c5f946001600160a01b03165f525f51602061295d5f395f51905f5260205260405f2090565b6001600160a01b0381168015159081611452575b5080611449575b15610cbe57610cb2610c3c8261142061144394610c818988612806565b6001600160a01b03165f525f51602061295d5f395f51905f5260205260405f2090565b926113e8565b50828410611403565b6001915014155f6113fc565b5061146b610d82826128bc565b6113a9565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff821117610afa57604052565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206109919381815201916114a6565b6040513d5f823e3d90fd5b634e487b7160e01b5f52603260045260245ffd5b91908110156115185760051b81013590603e1981360301821215610134570190565b6114e2565b35610991816101b6565b903590601e1981360301821215610134570180359067ffffffffffffffff82116101345760200191813603831361013457565b91908110156115185760051b81013590605e1981360301821215610134570190565b6040519061158b604083611484565b565b5f356001600160e01b03198116906115d6826001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b546115f56001600160a01b0382169160581b6001600160f81b03191690565b906001600160a01b03811661163e57505060e01c63bc197c81811463f23a6e6182141763150b7a0282141761163557506308c63e275f526020526024601cfd5b6020526020603cf35b5f51602061293d5f395f51905f52546001600160a01b0316801515926060929084611773575b6001600160f81b03198116607f60f91b0361170857505f809161168561284f565b90602082519201905afa926116986122ca565b935b15611700576116ac575b825160208401f35b803b15610134576116d75f92918392604051948580948193630b9dfbed60e11b83526004830161186e565b03925af1801561036d576116ec575b806116a4565b806103615f6116fa93611484565b816116e6565b835160208501fd5b6001600160f81b0319811661173e57505f809161172361284f565b906020825192019034905af1926117386122ca565b9361169a565b7fb96fcfe4000000000000000000000000000000000000000000000000000000005f526001600160f81b03191660045260245ffd5b925060405163d68f602560e01b81525f818061179436343360048501611848565b038183875af190811561036d575f916117af575b5092611664565b6117c391503d805f833e61038c8183611484565b856117a8565b67ffffffffffffffff8111610afa57601f01601f191660200190565b6020818303126101345780519067ffffffffffffffff8211610134570181601f8201121561013457805190611819826117c9565b926118276040519485611484565b8284526020838301011161013457815f9260208093018386015e8301015290565b61099193926001600160a01b03606093168252602082015281604082015201905f6114a6565b906020610991928181520190610d8b565b91906001600160a01b036118a76001600160a01b035f51602061293d5f395f51905f52541690565b16806118b7575061158b9261197b565b90916040519263d68f602560e01b84525f84806118d936343360048501611848565b038183875af193841561036d575f94611943575b506118f992939461197b565b803b15610134576119245f92918392604051948580948193630b9dfbed60e11b83526004830161186e565b03925af1801561036d576119355750565b806103615f61158b93611484565b6118f993945061195c903d805f833e61038c8183611484565b93926118ed565b90816020910312610134575180151581036101345790565b60405163ecd0596160e01b8152600160048201526001600160a01b038216939190602081602481885afa90811561036d575f91611a6c575b5015611a44576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168414611a1c576119f290612407565b823b1561013457611924925f92836040518096819582946306d61fe760e41b8452600484016114c6565b7fabc3af79000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe27c1dd8000000000000000000000000000000000000000000000000000000005f5260045ffd5b611a8e915060203d602011611a94575b611a868183611484565b810190611963565b5f6119b3565b503d611a7c565b91906001600160a01b03611ac36001600160a01b035f51602061293d5f395f51905f52541690565b1680611ad3575061158b92611b35565b90916040519263d68f602560e01b84525f8480611af536343360048501611848565b038183875af193841561036d575f94611b15575b506118f9929394611b35565b6118f9939450611b2e903d805f833e61038c8183611484565b9392611b09565b60405163ecd0596160e01b8152600260048201526001600160a01b038216939190602081602481885afa90811561036d575f91611b7c575b5015611a44576119f290612558565b611b95915060203d602011611a9457611a868183611484565b5f611b6d565b91906001600160a01b03611bc36001600160a01b035f51602061293d5f395f51905f52541690565b1680611bd3575061158b92611c72565b90916040519263d68f602560e01b84525f8480611bf536343360048501611848565b038183875af193841561036d575f94611c15575b506118f9929394611c72565b6118f9939450611c2e903d805f833e61038c8183611484565b9392611c09565b15611c3d5750565b6001600160a01b03907f741cbe03000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b60405163ecd0596160e01b81526004808201526001600160a01b038216939190602081602481885afa90811561036d575f91611d18575b5015611a44576119f290611ce4611cd46001600160a01b035f51602061293d5f395f51905f52541690565b6001600160a01b03811615611c35565b6001600160a01b03166001600160a01b03195f51602061293d5f395f51905f525416175f51602061293d5f395f51905f5255565b611d31915060203d602011611a9457611a868183611484565b5f611ca9565b91906001600160a01b03611d5f6001600160a01b035f51602061293d5f395f51905f52541690565b1680611d6f575061158b92611f13565b90916040519263d68f602560e01b84525f8480611d9136343360048501611848565b038183875af193841561036d575f94611db1575b506118f9929394611f13565b6118f9939450611dca903d805f833e61038c8183611484565b9392611da5565b906004116101345790600490565b909291928360051161013457831161013457600501916004190190565b919091356001600160e01b031981169260048110611e18575050565b6001600160e01b0319929350829060040360031b1b161690565b90600410156115185760040190565b15611e4857565b7f867a1dcf000000000000000000000000000000000000000000000000000000005f5260045ffd5b929192611e7c826117c9565b91611e8a6040519384611484565b829481845281830111610134578281602093845f960137010152565b15611ead57565b7fc001660b000000000000000000000000000000000000000000000000000000005f5260045ffd5b15611edd5750565b6001600160e01b0319907fa56a04dd000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90916001600160a01b0382169160405163ecd0596160e01b815260208180611f4360048201906003602083019252565b0381875afa90811561036d575f9161214f575b5015611a445761207b84612044611fd5611fce8680611fac611f9f611f9183611f8b611f856120da9e8c611dd1565b90611dfc565b99611e32565b356001600160f81b03191690565b6001600160f81b03191690565b9a6001600160f81b03198c16158015612138575b611fc990611e41565b611ddf565b3691611e70565b966120046001600160e01b031984166306d61fe760e41b811490811561210e575b8115612105575b5015611ea6565b61201983612014610d8282612648565b611ed5565b61203361202461157c565b6001600160a01b039096168652565b6001600160f81b0319166020850152565b6001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b8151815460209093015174ff000000000000000000000000000000000000000060589190911c167fffffffffffffffffffffff0000000000000000000000000000000000000000009093166001600160a01b0390911617919091179055565b803b15610134576119245f929183926040519485809481936306d61fe760e41b83526004830161186e565b9050155f611ffd565b7f8a91b0e30000000000000000000000000000000000000000000000000000000081149150611ff6565b50607f60f91b6001600160f81b03198d1614611fc0565b612168915060203d602011611a9457611a868183611484565b5f611f56565b9291906001600160a01b036121976001600160a01b035f51602061293d5f395f51905f52541690565b16806121a7575061158b93612248565b916040939193519363d68f602560e01b85525f85806121cb36343360048501611848565b038183885af194851561036d575f956121eb575b506118f9939495612248565b6118f9949550612204903d805f833e61038c8183611484565b94936121df565b156122135750565b6001600160a01b03907fc689cd97000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b60405163ecd0596160e01b8152600481018290526001600160a01b038316949290602081602481895afa90811561036d575f916122ab575b5015611a4457816122a66122966119f294612692565b6001600160a01b0381161561220b565b6126f5565b6122c4915060203d602011611a9457611a868183611484565b5f612280565b3d156122f4573d906122db826117c9565b916122e96040519384611484565b82523d5f602084013e565b606090565b60015f525f51602061295d5f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13546001600160a01b031661236c5760015f525f51602061295d5f395f51905f5260205261158b60405f2060016001600160a01b0319825416179055565b7f53c85e66000000000000000000000000000000000000000000000000000000005f5260045ffd5b60015f525f51602061291d5f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b031661236c5760015f525f51602061291d5f395f51905f5260205261158b60405f2060016001600160a01b0319825416179055565b6001600160a01b0381168015801561254e575b61253c575f9081525f51602061291d5f395f51905f5260205260409020546001600160a01b03166125085760015f525f51602061291d5f395f51905f5260205261158b906124cd61248a7ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7610c3c565b6124b2835f51602061291d5f395f51905f52906001600160a01b03165f5260205260405f2090565b906001600160a01b03166001600160a01b0319825416179055565b60015f525f51602061291d5f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c76124b2565b7f40d3d1a4000000000000000000000000000000000000000000000000000000005f526001600160a01b031660045260245ffd5b637c84ecfb60e01b5f5260045260245ffd5b506001811461241a565b6001600160a01b0381168015801561263e575b61253c575f9081525f51602061295d5f395f51905f5260205260409020546001600160a01b03166125085760015f525f51602061295d5f395f51905f5260205261158b906126036125db7fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13610c3c565b6124b2835f51602061295d5f395f51905f52906001600160a01b03165f5260205260405f2090565b60015f525f51602061295d5f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a136124b2565b506001811461256b565b61268b6001600160a01b03916001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b5416151590565b6008036126c7576001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f06541690565b6001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f05541690565b6008810361275857506001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f065416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0655565b6009146127625750565b6001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f055416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0555565b67ffffffffffffffff8111610afa5760051b60200190565b906127de826127bc565b6127eb6040519182611484565b82815280926127fc601f19916127bc565b0190602036910137565b80518210156115185760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f19811461283c5760010190565b61281a565b5f1981019190821161283c57565b60405190602036830101604052816014360181525f602036920137604051601481016040523360601b9052565b6001600160a01b031680600114159081612894575090565b90505f525f51602061291d5f395f51905f526020526001600160a01b0360405f205416151590565b6001600160a01b0316806001141590816128d4575090565b90505f525f51602061295d5f395f51905f526020526001600160a01b0360405f20541615159056fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef1230bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f030bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01a164736f6c634300081b000a0000000000000000000000000000000055c766a7060797fbc7be40c08b296b7200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000

Deployed Bytecode

0x60806040526004361015610015575b3661158d57005b5f3560e01c80630a664dba146101255780630b3dc3541461012057806310b7fca9146100f8578063112d3a7d1461011b578063220911871461010c578063310259841461011657806334ea61a51461011157806341bede031461010c578063481ddd231461010757806354ed06d5146101025780635faac46b146100fd5780636d583e36146100f857806384b0196e146100f357806386437876146100ee5780639517e29f146100e9578063a71763a8146100e9578063a8a33cf2146100e45763ea5f61d00361000e57611374565b61117c565b611173565b610f80565b610daf565b610232565b610bc8565b610aff565b610a41565b61050b565b610994565b61089a565b6103d8565b610173565b610138565b5f91031261013457565b5f80fd5b34610134575f3660031901126101345760206001600160a01b035f51602061293d5f395f51905f5254166001600160a01b0360405191168152f35b34610134575f3660031901126101345760206040516001600160a01b037f0000000000000000000000000000000055c766a7060797fbc7be40c08b296b72168152f35b6001600160a01b0381160361013457565b9181601f840112156101345782359167ffffffffffffffff8311610134576020838186019501011161013457565b9060406003198301126101345760043561020e816101b6565b916024359067ffffffffffffffff82116101345761022e916004016101c7565b9091565b61023b366101f5565b6102469291926122f9565b61024e612394565b6001600160a01b036102746001600160a01b035f51602061293d5f395f51905f52541690565b16806102be5750906102986102b9925f5160206128fd5f395f51905f52948361197b565b60408051600181526001600160a01b03909216602083015290918291820190565b0390a1005b906040519363d68f602560e01b85525f85806102df36343360048501611848565b038183875af194851561036d575f95610372575b50906102ff918461197b565b803b156101345761032a5f93918492604051958680948193630b9dfbed60e11b83526004830161186e565b03925af190811561036d575f5160206128fd5f395f51905f52926102b992610353575b50610298565b806103615f61036793611484565b8061012a565b5f61034d565b6114d7565b6102ff92919550610394903d805f833e61038c8183611484565b8101906117e5565b9490916102f3565b606060031982011261013457600435916024356103b8816101b6565b916044359067ffffffffffffffff82116101345761022e916004016101c7565b34610134576103e63661039c565b5050505060206040515f8152f35b9181601f840112156101345782359167ffffffffffffffff8311610134576020808501948460051b01011161013457565b908160409103126101345790565b9060c06003198301126101345760043567ffffffffffffffff8111610134578261045f916004016101c7565b9290929160243567ffffffffffffffff81116101345782610482916004016103f4565b9290929160443567ffffffffffffffff811161013457826104a5916004016103f4565b9290929160643567ffffffffffffffff811161013457826104c891600401610425565b9160843567ffffffffffffffff811161013457816104e8916004016103f4565b9290929160a4359067ffffffffffffffff82116101345761022e916004016103f4565b61051436610433565b9890996105289892989793979694966122f9565b610530612394565b6001600160a01b037f0000000000000000000000000000000055c766a7060797fbc7be40c08b296b721691823b1561013457610585925f92836040518096819582946306d61fe760e41b8452600484016114c6565b03925af1801561036d57610886575b505f5b82811061081a575050505f5b82811061078d575050506105c56105b98261151d565b6001600160a01b031690565b61072f575b505f5b828110610693575050505f5b8181106105e257005b806105fe6105b960206105f8600195878961155a565b0161151d565b1561068e5761064361061182858761155a565b3561062260206105f885888a61155a565b9061063b61063185888a61155a565b6040810190611527565b92909161216e565b5f5160206128fd5f395f51905f5261065c82858761155a565b3561066d60206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b016105d9565b610688565b806106ac6105b96106a760019487876114f6565b61151d565b1561072a576106e06106c26106a78387876114f6565b6106da6106d08488886114f6565b6020810190611527565b91611d37565b5f5160206128fd5f395f51905f526107206106ff6106a78488886114f6565b60408051600381526001600160a01b03909216602083015290918291820190565b0390a15b016105cd565b610724565b610784610763826106a76107505f5160206128fd5f395f51905f529561151d565b61075d6020840184611527565b91611b9b565b60408051600481526001600160a01b03909216602083015290918291820190565b0390a15f6105ca565b806107a16105b96106a760019487876114f6565b15610815576107cb6107b76106a78387876114f6565b6107c56106d08488886114f6565b91611a9b565b5f5160206128fd5f395f51905f5261080b6107ea6106a78488886114f6565b60408051600281526001600160a01b03909216602083015290918291820190565b0390a15b016105a3565b61080f565b8061082e6105b96106a760019487876114f6565b15610881576108586108446106a78387876114f6565b6108526106d08488886114f6565b9161187f565b5f5160206128fd5f395f51905f526108776102986106a78488886114f6565b0390a15b01610597565b61087b565b806103615f61089493611484565b5f610594565b5f60203660031901126101345760043567ffffffffffffffff8111610134576108c79036906004016101c7565b6001600160a01b037f0000000000000000000000000000000055c766a7060797fbc7be40c08b296b721691823b1561013457610923925f92836040518096819582946306d61fe760e41b845260206004850181815201916114a6565b03925af1801561036d57610935575080f35b61094191505f90611484565b005b60406003198201126101345760043567ffffffffffffffff8111610134578161096e916004016103f4565b929092916024359067ffffffffffffffff82116101345761099191600401610425565b90565b34610134576109a236610943565b91906109ac6122f9565b6109b4612394565b5f5b8181106109f757836001600160a01b036109cf8261151d565b166109d657005b6102b9610763826106a76107505f5160206128fd5f395f51905f529561151d565b80610a19610a0b6106a760019486886114f6565b6108526106d08487896114f6565b5f5160206128fd5f395f51905f52610a386102986106a78487896114f6565b0390a1016109b6565b34610134576020366003190112610134576004356001600160e01b03198116810361013457610aa1906001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b60405190604082019082821067ffffffffffffffff831117610afa576040918252546001600160a01b03811680845260589190911b6001600160f81b0319166020938401819052825190815292830152819081015b0390f35b611470565b610b0836610943565b9190610b126122f9565b610b1a612394565b5f5b818110610b3557836001600160a01b036109cf8261151d565b80610b49610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f52610b686102986106a78487896114f6565b0390a101610b1c565b90929192604082016040835281518091526020606084019201905f5b818110610ba9575050506001600160a01b036020919416910152565b82516001600160a01b0316845260209384019390920191600101610b8d565b3461013457604036600319011261013457600435610be5816101b6565b6024359060016001600160a01b038216141580610d75575b610d5a578115610d325790610c11816127d4565b610c49610c3c5f946001600160a01b03165f525f51602061291d5f395f51905f5260205260405f2090565b546001600160a01b031690565b6001600160a01b0381168015159081610d26575b5080610d1d575b15610cbe57610cb2610c3c82610c8f610cb894610c818988612806565b906001600160a01b03169052565b6001600160a01b03165f525f51602061291d5f395f51905f5260205260405f2090565b9361282e565b92610c49565b908360016001600160a01b038416141580610d14575b610cea575b8152610af660405192839283610b71565b9150610d0e610d01610cfb84612841565b83612806565b516001600160a01b031690565b91610cd9565b50801515610cd4565b50828410610c64565b6001915014155f610c5d565b7ff7250817000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c84ecfb60e01b5f526001600160a01b031660045260245ffd5b50610d86610d828261287c565b1590565b610bfd565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610134575f36600319011261013457610e6d6040610e7a815191610dd48184611484565b600e83527f4e65787573426f6f74737472617000000000000000000000000000000000000060208401528051610e0a8282611484565b600581527f312e332e30000000000000000000000000000000000000000000000000000000602082015281519485947f0f00000000000000000000000000000000000000000000000000000000000000865260e0602087015260e0860190610d8b565b9184830390850152610d8b565b4660608301523060808301525f60a083015281810360c083015260206060519182815201906080905f5b818110610eb2575050500390f35b8251845285945060209384019390920191600101610ea4565b9060a06003198301126101345760043567ffffffffffffffff81116101345782610ef7916004016103f4565b9290929160243567ffffffffffffffff81116101345782610f1a916004016103f4565b9290929160443567ffffffffffffffff81116101345782610f3d91600401610425565b9160643567ffffffffffffffff81116101345781610f5d916004016103f4565b929092916084359067ffffffffffffffff82116101345761022e916004016103f4565b610f8936610ecb565b96610f9b9891989692959394966122f9565b610fa3612394565b5f5b818110611137575050505f5b8281106110df575050505f5b82811061108757505050610fd36105b98261151d565b61105d575b505f5b818110610fe457005b80610ffa6105b960206105f8600195878961155a565b156110585761100d61061182858761155a565b5f5160206128fd5f395f51905f5261102682858761155a565b3561103760206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b01610fdb565b611052565b61107e610763826106a76107505f5160206128fd5f395f51905f529561151d565b0390a15f610fd8565b8061109b6105b96106a760019487876114f6565b156110da576110b16106c26106a78387876114f6565b5f5160206128fd5f395f51905f526110d06106ff6106a78488886114f6565b0390a15b01610fbd565b6110d4565b806110f36105b96106a760019487876114f6565b15611132576111096107b76106a78387876114f6565b5f5160206128fd5f395f51905f526111286107ea6106a78488886114f6565b0390a15b01610fb1565b61112c565b8061114b610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f5261116a6102986106a78487896114f6565b0390a101610fa5565b6109413661039c565b346101345761118a36610ecb565b9661119c9891989692959394966122f9565b6111a4612394565b5f5b818110611338575050505f5b8281106112e0575050505f5b828110611288575050506111d46105b98261151d565b61125e575b505f5b8181106111e557005b806111fb6105b960206105f8600195878961155a565b156112595761120e61061182858761155a565b5f5160206128fd5f395f51905f5261122782858761155a565b3561123860206105f885888a61155a565b604080519283526001600160a01b0391909116602083015290a15b016111dc565b611253565b61127f610763826106a76107505f5160206128fd5f395f51905f529561151d565b0390a15f6111d9565b8061129c6105b96106a760019487876114f6565b156112db576112b26106c26106a78387876114f6565b5f5160206128fd5f395f51905f526112d16106ff6106a78488886114f6565b0390a15b016111be565b6112d5565b806112f46105b96106a760019487876114f6565b156113335761130a6107b76106a78387876114f6565b5f5160206128fd5f395f51905f526113296107ea6106a78488886114f6565b0390a15b016111b2565b61132d565b8061134c610a0b6106a760019486886114f6565b5f5160206128fd5f395f51905f5261136b6102986106a78487896114f6565b0390a1016111a6565b3461013457604036600319011261013457600435611391816101b6565b6024359060016001600160a01b03821614158061145e575b610d5a578115610d3257906113bd816127d4565b6113e8610c3c5f946001600160a01b03165f525f51602061295d5f395f51905f5260205260405f2090565b6001600160a01b0381168015159081611452575b5080611449575b15610cbe57610cb2610c3c8261142061144394610c818988612806565b6001600160a01b03165f525f51602061295d5f395f51905f5260205260405f2090565b926113e8565b50828410611403565b6001915014155f6113fc565b5061146b610d82826128bc565b6113a9565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff821117610afa57604052565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206109919381815201916114a6565b6040513d5f823e3d90fd5b634e487b7160e01b5f52603260045260245ffd5b91908110156115185760051b81013590603e1981360301821215610134570190565b6114e2565b35610991816101b6565b903590601e1981360301821215610134570180359067ffffffffffffffff82116101345760200191813603831361013457565b91908110156115185760051b81013590605e1981360301821215610134570190565b6040519061158b604083611484565b565b5f356001600160e01b03198116906115d6826001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b546115f56001600160a01b0382169160581b6001600160f81b03191690565b906001600160a01b03811661163e57505060e01c63bc197c81811463f23a6e6182141763150b7a0282141761163557506308c63e275f526020526024601cfd5b6020526020603cf35b5f51602061293d5f395f51905f52546001600160a01b0316801515926060929084611773575b6001600160f81b03198116607f60f91b0361170857505f809161168561284f565b90602082519201905afa926116986122ca565b935b15611700576116ac575b825160208401f35b803b15610134576116d75f92918392604051948580948193630b9dfbed60e11b83526004830161186e565b03925af1801561036d576116ec575b806116a4565b806103615f6116fa93611484565b816116e6565b835160208501fd5b6001600160f81b0319811661173e57505f809161172361284f565b906020825192019034905af1926117386122ca565b9361169a565b7fb96fcfe4000000000000000000000000000000000000000000000000000000005f526001600160f81b03191660045260245ffd5b925060405163d68f602560e01b81525f818061179436343360048501611848565b038183875af190811561036d575f916117af575b5092611664565b6117c391503d805f833e61038c8183611484565b856117a8565b67ffffffffffffffff8111610afa57601f01601f191660200190565b6020818303126101345780519067ffffffffffffffff8211610134570181601f8201121561013457805190611819826117c9565b926118276040519485611484565b8284526020838301011161013457815f9260208093018386015e8301015290565b61099193926001600160a01b03606093168252602082015281604082015201905f6114a6565b906020610991928181520190610d8b565b91906001600160a01b036118a76001600160a01b035f51602061293d5f395f51905f52541690565b16806118b7575061158b9261197b565b90916040519263d68f602560e01b84525f84806118d936343360048501611848565b038183875af193841561036d575f94611943575b506118f992939461197b565b803b15610134576119245f92918392604051948580948193630b9dfbed60e11b83526004830161186e565b03925af1801561036d576119355750565b806103615f61158b93611484565b6118f993945061195c903d805f833e61038c8183611484565b93926118ed565b90816020910312610134575180151581036101345790565b60405163ecd0596160e01b8152600160048201526001600160a01b038216939190602081602481885afa90811561036d575f91611a6c575b5015611a44576001600160a01b037f0000000000000000000000000000000055c766a7060797fbc7be40c08b296b72168414611a1c576119f290612407565b823b1561013457611924925f92836040518096819582946306d61fe760e41b8452600484016114c6565b7fabc3af79000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe27c1dd8000000000000000000000000000000000000000000000000000000005f5260045ffd5b611a8e915060203d602011611a94575b611a868183611484565b810190611963565b5f6119b3565b503d611a7c565b91906001600160a01b03611ac36001600160a01b035f51602061293d5f395f51905f52541690565b1680611ad3575061158b92611b35565b90916040519263d68f602560e01b84525f8480611af536343360048501611848565b038183875af193841561036d575f94611b15575b506118f9929394611b35565b6118f9939450611b2e903d805f833e61038c8183611484565b9392611b09565b60405163ecd0596160e01b8152600260048201526001600160a01b038216939190602081602481885afa90811561036d575f91611b7c575b5015611a44576119f290612558565b611b95915060203d602011611a9457611a868183611484565b5f611b6d565b91906001600160a01b03611bc36001600160a01b035f51602061293d5f395f51905f52541690565b1680611bd3575061158b92611c72565b90916040519263d68f602560e01b84525f8480611bf536343360048501611848565b038183875af193841561036d575f94611c15575b506118f9929394611c72565b6118f9939450611c2e903d805f833e61038c8183611484565b9392611c09565b15611c3d5750565b6001600160a01b03907f741cbe03000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b60405163ecd0596160e01b81526004808201526001600160a01b038216939190602081602481885afa90811561036d575f91611d18575b5015611a44576119f290611ce4611cd46001600160a01b035f51602061293d5f395f51905f52541690565b6001600160a01b03811615611c35565b6001600160a01b03166001600160a01b03195f51602061293d5f395f51905f525416175f51602061293d5f395f51905f5255565b611d31915060203d602011611a9457611a868183611484565b5f611ca9565b91906001600160a01b03611d5f6001600160a01b035f51602061293d5f395f51905f52541690565b1680611d6f575061158b92611f13565b90916040519263d68f602560e01b84525f8480611d9136343360048501611848565b038183875af193841561036d575f94611db1575b506118f9929394611f13565b6118f9939450611dca903d805f833e61038c8183611484565b9392611da5565b906004116101345790600490565b909291928360051161013457831161013457600501916004190190565b919091356001600160e01b031981169260048110611e18575050565b6001600160e01b0319929350829060040360031b1b161690565b90600410156115185760040190565b15611e4857565b7f867a1dcf000000000000000000000000000000000000000000000000000000005f5260045ffd5b929192611e7c826117c9565b91611e8a6040519384611484565b829481845281830111610134578281602093845f960137010152565b15611ead57565b7fc001660b000000000000000000000000000000000000000000000000000000005f5260045ffd5b15611edd5750565b6001600160e01b0319907fa56a04dd000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90916001600160a01b0382169160405163ecd0596160e01b815260208180611f4360048201906003602083019252565b0381875afa90811561036d575f9161214f575b5015611a445761207b84612044611fd5611fce8680611fac611f9f611f9183611f8b611f856120da9e8c611dd1565b90611dfc565b99611e32565b356001600160f81b03191690565b6001600160f81b03191690565b9a6001600160f81b03198c16158015612138575b611fc990611e41565b611ddf565b3691611e70565b966120046001600160e01b031984166306d61fe760e41b811490811561210e575b8115612105575b5015611ea6565b61201983612014610d8282612648565b611ed5565b61203361202461157c565b6001600160a01b039096168652565b6001600160f81b0319166020850152565b6001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b8151815460209093015174ff000000000000000000000000000000000000000060589190911c167fffffffffffffffffffffff0000000000000000000000000000000000000000009093166001600160a01b0390911617919091179055565b803b15610134576119245f929183926040519485809481936306d61fe760e41b83526004830161186e565b9050155f611ffd565b7f8a91b0e30000000000000000000000000000000000000000000000000000000081149150611ff6565b50607f60f91b6001600160f81b03198d1614611fc0565b612168915060203d602011611a9457611a868183611484565b5f611f56565b9291906001600160a01b036121976001600160a01b035f51602061293d5f395f51905f52541690565b16806121a7575061158b93612248565b916040939193519363d68f602560e01b85525f85806121cb36343360048501611848565b038183885af194851561036d575f956121eb575b506118f9939495612248565b6118f9949550612204903d805f833e61038c8183611484565b94936121df565b156122135750565b6001600160a01b03907fc689cd97000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b60405163ecd0596160e01b8152600481018290526001600160a01b038316949290602081602481895afa90811561036d575f916122ab575b5015611a4457816122a66122966119f294612692565b6001600160a01b0381161561220b565b6126f5565b6122c4915060203d602011611a9457611a868183611484565b5f612280565b3d156122f4573d906122db826117c9565b916122e96040519384611484565b82523d5f602084013e565b606090565b60015f525f51602061295d5f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13546001600160a01b031661236c5760015f525f51602061295d5f395f51905f5260205261158b60405f2060016001600160a01b0319825416179055565b7f53c85e66000000000000000000000000000000000000000000000000000000005f5260045ffd5b60015f525f51602061291d5f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7546001600160a01b031661236c5760015f525f51602061291d5f395f51905f5260205261158b60405f2060016001600160a01b0319825416179055565b6001600160a01b0381168015801561254e575b61253c575f9081525f51602061291d5f395f51905f5260205260409020546001600160a01b03166125085760015f525f51602061291d5f395f51905f5260205261158b906124cd61248a7ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c7610c3c565b6124b2835f51602061291d5f395f51905f52906001600160a01b03165f5260205260405f2090565b906001600160a01b03166001600160a01b0319825416179055565b60015f525f51602061291d5f395f51905f526020527ffe44ceacbf4f03c6ac19f86826dd265fa9ec25125e8b1766c207f24cd3bc73c76124b2565b7f40d3d1a4000000000000000000000000000000000000000000000000000000005f526001600160a01b031660045260245ffd5b637c84ecfb60e01b5f5260045260245ffd5b506001811461241a565b6001600160a01b0381168015801561263e575b61253c575f9081525f51602061295d5f395f51905f5260205260409020546001600160a01b03166125085760015f525f51602061295d5f395f51905f5260205261158b906126036125db7fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a13610c3c565b6124b2835f51602061295d5f395f51905f52906001600160a01b03165f5260205260405f2090565b60015f525f51602061295d5f395f51905f526020527fbdfeb076d903611fa58576955630d640569633049bcf40ad9c22db9251b54a136124b2565b506001811461256b565b61268b6001600160a01b03916001600160e01b0319165f527f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0260205260405f2090565b5416151590565b6008036126c7576001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f06541690565b6001600160a01b037f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f05541690565b6008810361275857506001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f065416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0655565b6009146127625750565b6001600160a01b03166001600160a01b03197f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f055416177f0bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f0555565b67ffffffffffffffff8111610afa5760051b60200190565b906127de826127bc565b6127eb6040519182611484565b82815280926127fc601f19916127bc565b0190602036910137565b80518210156115185760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b5f19811461283c5760010190565b61281a565b5f1981019190821161283c57565b60405190602036830101604052816014360181525f602036920137604051601481016040523360601b9052565b6001600160a01b031680600114159081612894575090565b90505f525f51602061291d5f395f51905f526020526001600160a01b0360405f205416151590565b6001600160a01b0316806001141590816128d4575090565b90505f525f51602061295d5f395f51905f526020526001600160a01b0360405f20541615159056fed21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef1230bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f000bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f030bb70095b32b9671358306b0339b4c06e7cbd8cb82505941fba30d1eb5b82f01a164736f6c634300081b000a

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

0000000000000000000000000000000055c766a7060797fbc7be40c08b296b7200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000

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

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000055c766a7060797fbc7be40c08b296b72
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

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.