Sepolia Testnet

Contract

0x00000000000017c61b5bEe81050EC8eFc9c6fecd

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Add Stake82915442025-05-09 19:22:2421 days ago1746818544IN
0x00000000...Fc9c6fecd
0 ETH0.000000030.00100001
Add Stake82915052025-05-09 19:14:3621 days ago1746818076IN
0x00000000...Fc9c6fecd
0 ETH0.000000030.00108761
Add Stake73003022024-12-17 21:58:36164 days ago1734472716IN
0x00000000...Fc9c6fecd
0.1 ETH0.00009191.52416753

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x6100513d84426132025-05-31 0:05:3610 hrs ago1748649936
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84409632025-05-30 18:35:0016 hrs ago1748630100
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84408832025-05-30 18:18:3616 hrs ago1748629116
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84403052025-05-30 16:22:0018 hrs ago1748622120
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84402132025-05-30 16:03:3618 hrs ago1748621016
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84401692025-05-30 15:54:4819 hrs ago1748620488
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84401022025-05-30 15:41:2419 hrs ago1748619684
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84399652025-05-30 15:14:0019 hrs ago1748618040
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84399422025-05-30 15:09:1219 hrs ago1748617752
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84340552025-05-29 19:31:0039 hrs ago1748547060
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84276412025-05-28 22:06:002 days ago1748469960
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84270122025-05-28 20:00:002 days ago1748462400
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84180342025-05-27 14:01:123 days ago1748354472
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84175422025-05-27 12:22:003 days ago1748348520
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84117282025-05-26 16:56:484 days ago1748278608
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d84055562025-05-25 19:58:125 days ago1748203092
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83900912025-05-23 15:08:247 days ago1748012904
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83763482025-05-21 17:12:369 days ago1747847556
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83597362025-05-19 9:35:3612 days ago1747647336
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83389822025-05-16 12:03:3614 days ago1747397016
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83389702025-05-16 12:01:1214 days ago1747396872
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83382032025-05-16 9:26:1215 days ago1747387572
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83334192025-05-15 17:28:0015 days ago1747330080
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83331412025-05-15 16:32:1215 days ago1747326732
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
0x6100513d83306562025-05-15 8:14:2416 days ago1747296864
0x00000000...Fc9c6fecd
 Contract Creation0 ETH
View All Internal Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AccountFactory

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {LibClone} from "solady/utils/LibClone.sol";

import {ModularAccount} from "../account/ModularAccount.sol";
import {SemiModularAccountBytecode} from "../account/SemiModularAccountBytecode.sol";

/// @title Account Factory
/// @author Alchemy
/// @notice Factory contract to deploy modular accounts. Allows creation of both modular and semi-modular accounts
/// (the bytecode variant).
contract AccountFactory is Ownable2Step {
    ModularAccount public immutable ACCOUNT_IMPL;
    SemiModularAccountBytecode public immutable SEMI_MODULAR_ACCOUNT_IMPL;
    IEntryPoint public immutable ENTRY_POINT;
    address public immutable SINGLE_SIGNER_VALIDATION_MODULE;
    address public immutable WEBAUTHN_VALIDATION_MODULE;

    event ModularAccountDeployed(address indexed account, address indexed owner, uint256 salt);
    event SemiModularAccountDeployed(address indexed account, address indexed owner, uint256 salt);
    event WebAuthnModularAccountDeployed(
        address indexed account, uint256 indexed ownerX, uint256 indexed ownerY, uint256 salt
    );

    error InvalidAction();
    error TransferFailed();

    constructor(
        IEntryPoint _entryPoint,
        ModularAccount _accountImpl,
        SemiModularAccountBytecode _semiModularImpl,
        address _singleSignerValidationModule,
        address _webAuthnValidationModule,
        address owner
    ) Ownable(owner) {
        ENTRY_POINT = _entryPoint;
        ACCOUNT_IMPL = _accountImpl;
        SEMI_MODULAR_ACCOUNT_IMPL = _semiModularImpl;
        SINGLE_SIGNER_VALIDATION_MODULE = _singleSignerValidationModule;
        WEBAUTHN_VALIDATION_MODULE = _webAuthnValidationModule;
    }

    /// @notice Create an account with the single singer validation module installed, and return its address.
    /// @dev Returns the address even if the account is already deployed.
    /// Note that during user operation execution, this method is called only if the account is not deployed.
    /// This method returns an existing account address so that entryPoint.getSenderAddress() would work even after
    /// account creation.
    /// @param owner The owner of the account.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The address of the created account.
    function createAccount(address owner, uint256 salt, uint32 entityId) external returns (ModularAccount) {
        bytes32 combinedSalt = getSalt(owner, salt, entityId);

        // LibClone short-circuits if it's already deployed.
        (bool alreadyDeployed, address instance) =
            LibClone.createDeterministicERC1967(address(ACCOUNT_IMPL), combinedSalt);

        // short circuit if exists
        if (!alreadyDeployed) {
            bytes memory moduleInstallData = abi.encode(entityId, owner);
            // point proxy to actual implementation and init plugins
            ModularAccount(payable(instance)).initializeWithValidation(
                ValidationConfigLib.pack(SINGLE_SIGNER_VALIDATION_MODULE, entityId, true, true, true),
                new bytes4[](0),
                moduleInstallData,
                new bytes[](0)
            );
            emit ModularAccountDeployed(instance, owner, salt);
        }

        return ModularAccount(payable(instance));
    }

    /// @notice Create a semi-modular account and return its address.
    /// @dev This only ever deploys semi-modular accounts with added bytecode since this is much less
    /// expensive than the storage-only variant, which should only be used for upgrades.
    /// @param owner The owner of the account.
    /// @param salt The salt to use for the account creation.
    /// @return The address of the created account.
    function createSemiModularAccount(address owner, uint256 salt) external returns (SemiModularAccountBytecode) {
        // both module address and entityId for fallback validations are hardcoded at the maximum value.
        bytes32 fullSalt = getSalt(owner, salt, type(uint32).max);

        bytes memory immutables = _getImmutableArgs(owner);

        // LibClone short-circuits if it's already deployed.
        (bool alreadyDeployed, address instance) =
            LibClone.createDeterministicERC1967(address(SEMI_MODULAR_ACCOUNT_IMPL), immutables, fullSalt);

        if (!alreadyDeployed) {
            emit SemiModularAccountDeployed(instance, owner, salt);
        }

        return SemiModularAccountBytecode(payable(instance));
    }

    /// @notice Create an account with the WebAuthn module installed, and return its address.
    /// @dev Returns the address even if the account is already deployed.
    /// Note that during user operation execution, this method is called only if the account is not deployed.
    /// This method returns an existing account address so that entryPoint.getSenderAddress() would work even after
    /// account creation.
    /// @param ownerX The x coordinate of the owner's public key.
    /// @param ownerY The y coordinate of the owner's public key.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The address of the created account.
    function createWebAuthnAccount(uint256 ownerX, uint256 ownerY, uint256 salt, uint32 entityId)
        external
        returns (ModularAccount)
    {
        bytes32 combinedSalt = getSaltWebAuthn(ownerX, ownerY, salt, entityId);

        // LibClone short-circuits if it's already deployed.
        (bool alreadyDeployed, address instance) =
            LibClone.createDeterministicERC1967(address(ACCOUNT_IMPL), combinedSalt);

        // short circuit if exists
        if (!alreadyDeployed) {
            bytes memory moduleInstallData = abi.encode(entityId, ownerX, ownerY);
            // point proxy to actual implementation and init plugins
            ModularAccount(payable(instance)).initializeWithValidation(
                ValidationConfigLib.pack(WEBAUTHN_VALIDATION_MODULE, entityId, true, true, true),
                new bytes4[](0),
                moduleInstallData,
                new bytes[](0)
            );
            emit WebAuthnModularAccountDeployed(instance, ownerX, ownerY, salt);
        }

        return ModularAccount(payable(instance));
    }

    /// @notice Add stake to the entry point contract.
    /// @param unstakeDelay The delay in seconds before the stake can be withdrawn.
    function addStake(uint32 unstakeDelay) external payable onlyOwner {
        ENTRY_POINT.addStake{value: msg.value}(unstakeDelay);
    }

    /// @notice Unlock the stake in the entry point contract.
    function unlockStake() external onlyOwner {
        ENTRY_POINT.unlockStake();
    }

    /// @notice Withdraw the stake from the entry point contract.
    /// @param withdrawAddress The address to withdraw the stake to.
    function withdrawStake(address payable withdrawAddress) external onlyOwner {
        ENTRY_POINT.withdrawStake(withdrawAddress);
    }

    /// @notice Withdraw funds from this contract.
    /// @dev Can be used to withdraw native currency or ERC-20 tokens.
    /// @param to The address to withdraw the funds to.
    /// @param token The address of the token to withdraw, or the zero address for native currency.
    /// @param amount The amount to withdraw.
    function withdraw(address payable to, address token, uint256 amount) external onlyOwner {
        if (token == address(0)) {
            (bool success,) = to.call{value: address(this).balance}("");
            if (!success) {
                revert TransferFailed();
            }
        } else {
            SafeERC20.safeTransfer(IERC20(token), to, amount);
        }
    }

    /// @notice Calculate the counterfactual address of this account as it would be returned by createAccount.
    /// @param owner The owner of the account.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The address of the account.
    function getAddress(address owner, uint256 salt, uint32 entityId) external view returns (address) {
        return LibClone.predictDeterministicAddressERC1967(
            address(ACCOUNT_IMPL), getSalt(owner, salt, entityId), address(this)
        );
    }

    /// @notice Calculate the counterfactual address of a semi-modular account as it would be returned by
    /// createSemiModularAccount.
    /// @param owner The owner of the account.
    /// @param salt The salt to use for the account creation.
    /// @return The address of the account.
    function getAddressSemiModular(address owner, uint256 salt) external view returns (address) {
        bytes32 fullSalt = getSalt(owner, salt, type(uint32).max);
        bytes memory immutables = _getImmutableArgs(owner);
        return _getAddressSemiModular(immutables, fullSalt);
    }

    /// @notice Calculate the counterfactual address of a webauthn account as it would be returned by
    /// createWebAuthnAccount.
    /// @param ownerX The x coordinate of the owner's public key.
    /// @param ownerY The y coordinate of the owner's public key.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The address of the account.
    function getAddressWebAuthn(uint256 ownerX, uint256 ownerY, uint256 salt, uint32 entityId)
        external
        view
        returns (address)
    {
        return LibClone.predictDeterministicAddressERC1967(
            address(ACCOUNT_IMPL), getSaltWebAuthn(ownerX, ownerY, salt, entityId), address(this)
        );
    }

    /// @notice Disable renouncing ownership.
    function renounceOwnership() public view override onlyOwner {
        revert InvalidAction();
    }

    /// @notice Get the full salt used for account creation.
    /// @dev To get the full salt used in createSemiModularAccount, use type(uint32).max for entityId.
    /// @param owner The owner of the account.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The full salt.
    function getSalt(address owner, uint256 salt, uint32 entityId) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(owner, salt, entityId));
    }

    /// @notice Get the full salt used for account creation using WebAuthn.
    /// @param ownerX The x coordinate of the owner's public key.
    /// @param ownerY The y coordinate of the owner's public key.
    /// @param salt The salt to use for the account creation.
    /// @param entityId The entity ID to use for the account creation.
    /// @return The full salt.
    function getSaltWebAuthn(uint256 ownerX, uint256 ownerY, uint256 salt, uint32 entityId)
        public
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(ownerX, ownerY, salt, entityId));
    }

    function _getAddressSemiModular(bytes memory immutables, bytes32 salt) internal view returns (address) {
        return LibClone.predictDeterministicAddressERC1967(
            address(SEMI_MODULAR_ACCOUNT_IMPL), immutables, salt, address(this)
        );
    }

    function _getImmutableArgs(address owner) private pure returns (bytes memory) {
        return abi.encodePacked(owner);
    }
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import {ModuleEntity, ValidationConfig, ValidationFlags} from "../interfaces/IModularAccount.sol";

// Validation config is a packed representation of a validation function and flags for its configuration.
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________CC______________ // ValidationFlags
// 0x__________________________________________________00000000000000 // unused

// ValidationFlags layout:
// 0b00000___ // unused
// 0b_____A__ // isGlobal
// 0b______B_ // isSignatureValidation
// 0b_______C // isUserOpValidation

library ValidationConfigLib {
    // is user op validation flag stored in last bit of the 25th byte
    bytes32 internal constant _VALIDATION_FLAG_IS_USER_OP = bytes32(uint256(1) << 56);
    // is signature validation flag stored in second to last bit of the 25th byte
    bytes32 internal constant _VALIDATION_FLAG_IS_SIGNATURE = bytes32(uint256(1) << 57);
    // is global flag stored in the third to last bit of the 25th byte
    bytes32 internal constant _VALIDATION_FLAG_IS_GLOBAL = bytes32(uint256(1) << 58);

    function pack(
        ModuleEntity _validationFunction,
        bool _isGlobal,
        bool _isSignatureValidation,
        bool _isUserOpValidation
    ) internal pure returns (ValidationConfig) {
        return ValidationConfig.wrap(
            bytes25(
                bytes25(ModuleEntity.unwrap(_validationFunction))
                    | bytes25(bytes32(_isGlobal ? _VALIDATION_FLAG_IS_GLOBAL : bytes32(0)))
                    | bytes25(bytes32(_isSignatureValidation ? _VALIDATION_FLAG_IS_SIGNATURE : bytes32(0)))
                    | bytes25(bytes32(_isUserOpValidation ? _VALIDATION_FLAG_IS_USER_OP : bytes32(0)))
            )
        );
    }

    function pack(
        address _module,
        uint32 _entityId,
        bool _isGlobal,
        bool _isSignatureValidation,
        bool _isUserOpValidation
    ) internal pure returns (ValidationConfig) {
        return ValidationConfig.wrap(
            bytes25(
                // module address stored in the first 20 bytes
                bytes25(bytes20(_module))
                // entityId stored in the 21st - 24th byte
                | bytes25(bytes24(uint192(_entityId)))
                    | bytes25(bytes32(_isGlobal ? _VALIDATION_FLAG_IS_GLOBAL : bytes32(0)))
                    | bytes25(bytes32(_isSignatureValidation ? _VALIDATION_FLAG_IS_SIGNATURE : bytes32(0)))
                    | bytes25(bytes32(_isUserOpValidation ? _VALIDATION_FLAG_IS_USER_OP : bytes32(0)))
            )
        );
    }

    function unpackUnderlying(ValidationConfig config)
        internal
        pure
        returns (address _module, uint32 _entityId, ValidationFlags flags)
    {
        bytes25 configBytes = ValidationConfig.unwrap(config);
        _module = address(bytes20(configBytes));
        _entityId = uint32(bytes4(configBytes << 160));
        flags = ValidationFlags.wrap(uint8(configBytes[24]));
    }

    function unpack(ValidationConfig config)
        internal
        pure
        returns (ModuleEntity _validationFunction, ValidationFlags flags)
    {
        bytes25 configBytes = ValidationConfig.unwrap(config);
        _validationFunction = ModuleEntity.wrap(bytes24(configBytes));
        flags = ValidationFlags.wrap(uint8(configBytes[24]));
    }

    function module(ValidationConfig config) internal pure returns (address) {
        return address(bytes20(ValidationConfig.unwrap(config)));
    }

    function entityId(ValidationConfig config) internal pure returns (uint32) {
        return uint32(bytes4(ValidationConfig.unwrap(config) << 160));
    }

    function moduleEntity(ValidationConfig config) internal pure returns (ModuleEntity) {
        return ModuleEntity.wrap(bytes24(ValidationConfig.unwrap(config)));
    }

    function isGlobal(ValidationConfig config) internal pure returns (bool) {
        return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_GLOBAL != 0;
    }

    function isGlobal(ValidationFlags flags) internal pure returns (bool) {
        return ValidationFlags.unwrap(flags) & 0x04 != 0;
    }

    function isSignatureValidation(ValidationConfig config) internal pure returns (bool) {
        return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_SIGNATURE != 0;
    }

    function isSignatureValidation(ValidationFlags flags) internal pure returns (bool) {
        return ValidationFlags.unwrap(flags) & 0x02 != 0;
    }

    function isUserOpValidation(ValidationConfig config) internal pure returns (bool) {
        return ValidationConfig.unwrap(config) & _VALIDATION_FLAG_IS_USER_OP != 0;
    }

    function isUserOpValidation(ValidationFlags flags) internal pure returns (bool) {
        return ValidationFlags.unwrap(flags) & 0x01 != 0;
    }
}

/**
 ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
 ** Only one instance required on each chain.
 **/
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */

import "./PackedUserOperation.sol";
import "./IStakeManager.sol";
import "./IAggregator.sol";
import "./INonceManager.sol";

interface IEntryPoint is IStakeManager, INonceManager {
    /***
     * An event emitted after each successful request.
     * @param userOpHash    - Unique identifier for the request (hash its entire content, except signature).
     * @param sender        - The account that generates this request.
     * @param paymaster     - If non-null, the paymaster that pays for this request.
     * @param nonce         - The nonce value from the request.
     * @param success       - True if the sender transaction succeeded, false if reverted.
     * @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation.
     * @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation,
     *                        validation and execution).
     */
    event UserOperationEvent(
        bytes32 indexed userOpHash,
        address indexed sender,
        address indexed paymaster,
        uint256 nonce,
        bool success,
        uint256 actualGasCost,
        uint256 actualGasUsed
    );

    /**
     * Account "sender" was deployed.
     * @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow.
     * @param sender     - The account that is deployed
     * @param factory    - The factory used to deploy this account (in the initCode)
     * @param paymaster  - The paymaster used by this UserOp
     */
    event AccountDeployed(
        bytes32 indexed userOpHash,
        address indexed sender,
        address factory,
        address paymaster
    );

    /**
     * An event emitted if the UserOperation "callData" reverted with non-zero length.
     * @param userOpHash   - The request unique identifier.
     * @param sender       - The sender of this request.
     * @param nonce        - The nonce used in the request.
     * @param revertReason - The return bytes from the (reverted) call to "callData".
     */
    event UserOperationRevertReason(
        bytes32 indexed userOpHash,
        address indexed sender,
        uint256 nonce,
        bytes revertReason
    );

    /**
     * An event emitted if the UserOperation Paymaster's "postOp" call reverted with non-zero length.
     * @param userOpHash   - The request unique identifier.
     * @param sender       - The sender of this request.
     * @param nonce        - The nonce used in the request.
     * @param revertReason - The return bytes from the (reverted) call to "callData".
     */
    event PostOpRevertReason(
        bytes32 indexed userOpHash,
        address indexed sender,
        uint256 nonce,
        bytes revertReason
    );

    /**
     * UserOp consumed more than prefund. The UserOperation is reverted, and no refund is made.
     * @param userOpHash   - The request unique identifier.
     * @param sender       - The sender of this request.
     * @param nonce        - The nonce used in the request.
     */
    event UserOperationPrefundTooLow(
        bytes32 indexed userOpHash,
        address indexed sender,
        uint256 nonce
    );

    /**
     * An event emitted by handleOps(), before starting the execution loop.
     * Any event emitted before this event, is part of the validation.
     */
    event BeforeExecution();

    /**
     * Signature aggregator used by the following UserOperationEvents within this bundle.
     * @param aggregator - The aggregator used for the following UserOperationEvents.
     */
    event SignatureAggregatorChanged(address indexed aggregator);

    /**
     * A custom revert error of handleOps, to identify the offending op.
     * Should be caught in off-chain handleOps simulation and not happen on-chain.
     * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.
     * NOTE: If simulateValidation passes successfully, there should be no reason for handleOps to fail on it.
     * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).
     * @param reason  - Revert reason. The string starts with a unique code "AAmn",
     *                  where "m" is "1" for factory, "2" for account and "3" for paymaster issues,
     *                  so a failure can be attributed to the correct entity.
     */
    error FailedOp(uint256 opIndex, string reason);

    /**
     * A custom revert error of handleOps, to report a revert by account or paymaster.
     * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).
     * @param reason  - Revert reason. see FailedOp(uint256,string), above
     * @param inner   - data from inner cought revert reason
     * @dev note that inner is truncated to 2048 bytes
     */
    error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner);

    error PostOpReverted(bytes returnData);

    /**
     * Error case when a signature aggregator fails to verify the aggregated signature it had created.
     * @param aggregator The aggregator that failed to verify the signature
     */
    error SignatureValidationFailed(address aggregator);

    // Return value of getSenderAddress.
    error SenderAddressResult(address sender);

    // UserOps handled, per aggregator.
    struct UserOpsPerAggregator {
        PackedUserOperation[] userOps;
        // Aggregator address
        IAggregator aggregator;
        // Aggregated signature
        bytes signature;
    }

    /**
     * Execute a batch of UserOperations.
     * No signature aggregator is used.
     * If any account requires an aggregator (that is, it returned an aggregator when
     * performing simulateValidation), then handleAggregatedOps() must be used instead.
     * @param ops         - The operations to execute.
     * @param beneficiary - The address to receive the fees.
     */
    function handleOps(
        PackedUserOperation[] calldata ops,
        address payable beneficiary
    ) external;

    /**
     * Execute a batch of UserOperation with Aggregators
     * @param opsPerAggregator - The operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts).
     * @param beneficiary      - The address to receive the fees.
     */
    function handleAggregatedOps(
        UserOpsPerAggregator[] calldata opsPerAggregator,
        address payable beneficiary
    ) external;

    /**
     * Generate a request Id - unique identifier for this request.
     * The request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid.
     * @param userOp - The user operation to generate the request ID for.
     * @return hash the hash of this UserOperation
     */
    function getUserOpHash(
        PackedUserOperation calldata userOp
    ) external view returns (bytes32);

    /**
     * Gas and return values during simulation.
     * @param preOpGas         - The gas used for validation (including preValidationGas)
     * @param prefund          - The required prefund for this operation
     * @param accountValidationData   - returned validationData from account.
     * @param paymasterValidationData - return validationData from paymaster.
     * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp)
     */
    struct ReturnInfo {
        uint256 preOpGas;
        uint256 prefund;
        uint256 accountValidationData;
        uint256 paymasterValidationData;
        bytes paymasterContext;
    }

    /**
     * Returned aggregated signature info:
     * The aggregator returned by the account, and its current stake.
     */
    struct AggregatorStakeInfo {
        address aggregator;
        StakeInfo stakeInfo;
    }

    /**
     * Get counterfactual sender address.
     * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.
     * This method always revert, and returns the address in SenderAddressResult error
     * @param initCode - The constructor code to be passed into the UserOperation.
     */
    function getSenderAddress(bytes memory initCode) external;

    error DelegateAndRevert(bool success, bytes ret);

    /**
     * Helper method for dry-run testing.
     * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result.
     *  The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace
     *  actual EntryPoint code is less convenient.
     * @param target a target contract to make a delegatecall from entrypoint
     * @param data data to pass to target in a delegatecall
     */
    function delegateAndRevert(address target, bytes calldata data) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

File 8 of 70 : LibClone.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Minimal proxy library.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
/// @author Minimal proxy by 0age (https://github.com/0age)
/// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
/// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
/// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy)
///
/// @dev Minimal proxy:
/// Although the sw0nt pattern saves 5 gas over the ERC1167 pattern during runtime,
/// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
/// which saves 4 gas over the ERC1167 pattern during runtime, and has the smallest bytecode.
/// - Automatically verified on Etherscan.
///
/// @dev Minimal proxy (PUSH0 variant):
/// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai.
/// It is optimized first for minimal runtime gas, then for minimal bytecode.
/// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as
/// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai.
/// Please use with caution.
/// - Automatically verified on Etherscan.
///
/// @dev Clones with immutable args (CWIA):
/// The implementation of CWIA here is does NOT append the immutable args into the calldata
/// passed into delegatecall. It is simply an ERC1167 minimal proxy with the immutable arguments
/// appended to the back of the runtime bytecode.
/// - Uses the identity precompile (0x4) to copy args during deployment.
///
/// @dev Minimal ERC1967 proxy:
/// An minimal ERC1967 proxy, intended to be upgraded with UUPS.
/// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.
/// - Automatically verified on Etherscan.
///
/// @dev Minimal ERC1967 proxy with immutable args:
/// - Uses the identity precompile (0x4) to copy args during deployment.
/// - Automatically verified on Etherscan.
///
/// @dev ERC1967I proxy:
/// An variant of the minimal ERC1967 proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// `implementation` address. The returned implementation is guaranteed to be valid if the
/// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`.
///
/// @dev ERC1967I proxy with immutable args:
/// An variant of the minimal ERC1967 proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// - Uses the identity precompile (0x4) to copy args during deployment.
///
/// @dev Minimal ERC1967 beacon proxy:
/// A minimal beacon proxy, intended to be upgraded with an upgradable beacon.
/// - Automatically verified on Etherscan.
///
/// @dev Minimal ERC1967 beacon proxy with immutable args:
/// - Uses the identity precompile (0x4) to copy args during deployment.
/// - Automatically verified on Etherscan.
///
/// @dev ERC1967I beacon proxy:
/// An variant of the minimal ERC1967 beacon proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// `implementation` address. The returned implementation is guaranteed to be valid if the
/// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`.
///
/// @dev ERC1967I proxy with immutable args:
/// An variant of the minimal ERC1967 beacon proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// - Uses the identity precompile (0x4) to copy args during deployment.
library LibClone {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The keccak256 of deployed code for the clone proxy,
    /// with the implementation set to `address(0)`.
    bytes32 internal constant CLONE_CODE_HASH =
        0x48db2cfdb2853fce0b464f1f93a1996469459df3ab6c812106074c4106a1eb1f;

    /// @dev The keccak256 of deployed code for the PUSH0 proxy,
    /// with the implementation set to `address(0)`.
    bytes32 internal constant PUSH0_CLONE_CODE_HASH =
        0x67bc6bde1b84d66e267c718ba44cf3928a615d29885537955cb43d44b3e789dc;

    /// @dev The keccak256 of deployed code for the ERC-1167 CWIA proxy,
    /// with the implementation set to `address(0)`.
    bytes32 internal constant CWIA_CODE_HASH =
        0x3cf92464268225a4513da40a34d967354684c32cd0edd67b5f668dfe3550e940;

    /// @dev The keccak256 of the deployed code for the ERC1967 proxy.
    bytes32 internal constant ERC1967_CODE_HASH =
        0xaaa52c8cc8a0e3fd27ce756cc6b4e70c51423e9b597b11f32d3e49f8b1fc890d;

    /// @dev The keccak256 of the deployed code for the ERC1967I proxy.
    bytes32 internal constant ERC1967I_CODE_HASH =
        0xce700223c0d4cea4583409accfc45adac4a093b3519998a9cbbe1504dadba6f7;

    /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy.
    bytes32 internal constant ERC1967_BEACON_PROXY_CODE_HASH =
        0x14044459af17bc4f0f5aa2f658cb692add77d1302c29fe2aebab005eea9d1162;

    /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy.
    bytes32 internal constant ERC1967I_BEACON_PROXY_CODE_HASH =
        0xf8c46d2793d5aa984eb827aeaba4b63aedcab80119212fce827309788735519a;

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

    /// @dev Unable to deploy the clone.
    error DeploymentFailed();

    /// @dev The salt must start with either the zero address or `by`.
    error SaltDoesNotStartWith();

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  MINIMAL PROXY OPERATIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a clone of `implementation`.
    function clone(address implementation) internal returns (address instance) {
        instance = clone(0, implementation);
    }

    /// @dev Deploys a clone of `implementation`.
    /// Deposits `value` ETH during deployment.
    function clone(uint256 value, address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * --------------------------------------------------------------------------+
             * CREATION (9 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                       |
             * --------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize     | r         |                              |
             * 3d         | RETURNDATASIZE    | 0 r       |                              |
             * 81         | DUP2              | r 0 r     |                              |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                              |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
             * f3         | RETURN            |           | [0..runSize): runtime code   |
             * --------------------------------------------------------------------------|
             * RUNTIME (44 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode  | Mnemonic       | Stack                  | Memory                |
             * --------------------------------------------------------------------------|
             *                                                                           |
             * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | 0                      |                       |
             * 3d      | RETURNDATASIZE | 0 0                    |                       |
             * 3d      | RETURNDATASIZE | 0 0 0                  |                       |
             * 3d      | RETURNDATASIZE | 0 0 0 0                |                       |
             *                                                                           |
             * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0 0 0            |                       |
             * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          |                       |
             * 3d      | RETURNDATASIZE | 0 0 cds 0 0 0 0        |                       |
             * 37      | CALLDATACOPY   | 0 0 0 0                | [0..cds): calldata    |
             *                                                                           |
             * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0 0 0            | [0..cds): calldata    |
             * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          | [0..cds): calldata    |
             * 73 addr | PUSH20 addr    | addr 0 cds 0 0 0 0     | [0..cds): calldata    |
             * 5a      | GAS            | gas addr 0 cds 0 0 0 0 | [0..cds): calldata    |
             * f4      | DELEGATECALL   | success 0 0            | [0..cds): calldata    |
             *                                                                           |
             * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds success 0 0        | [0..cds): calldata    |
             * 3d      | RETURNDATASIZE | rds rds success 0 0    | [0..cds): calldata    |
             * 93      | SWAP4          | 0 rds success 0 rds    | [0..cds): calldata    |
             * 80      | DUP1           | 0 0 rds success 0 rds  | [0..cds): calldata    |
             * 3e      | RETURNDATACOPY | success 0 rds          | [0..rds): returndata  |
             *                                                                           |
             * 60 0x2a | PUSH1 0x2a     | 0x2a success 0 rds     | [0..rds): returndata  |
             * 57      | JUMPI          | 0 rds                  | [0..rds): returndata  |
             *                                                                           |
             * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd      | REVERT         |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b      | JUMPDEST       | 0 rds                  | [0..rds): returndata  |
             * f3      | RETURN         |                        | [0..rds): returndata  |
             * --------------------------------------------------------------------------+
             */
            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            instance := create(value, 0x0c, 0x35)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Deploys a deterministic clone of `implementation` with `salt`.
    function cloneDeterministic(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = cloneDeterministic(0, implementation, salt);
    }

    /// @dev Deploys a deterministic clone of `implementation` with `salt`.
    /// Deposits `value` ETH during deployment.
    function cloneDeterministic(uint256 value, address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            instance := create2(value, 0x0c, 0x35, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the clone of `implementation`.
    function initCode(address implementation) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000)
            mstore(add(c, 0x28), implementation)
            mstore(add(c, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            mstore(c, 0x35) // Store the length.
            mstore(0x40, add(c, 0x60)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the clone of `implementation`.
    function initCodeHash(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            hash := keccak256(0x0c, 0x35)
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the address of the clone of `implementation`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          MINIMAL PROXY OPERATIONS (PUSH0 VARIANT)          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a PUSH0 clone of `implementation`.
    function clone_PUSH0(address implementation) internal returns (address instance) {
        instance = clone_PUSH0(0, implementation);
    }

    /// @dev Deploys a PUSH0 clone of `implementation`.
    /// Deposits `value` ETH during deployment.
    function clone_PUSH0(uint256 value, address implementation)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * --------------------------------------------------------------------------+
             * CREATION (9 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                       |
             * --------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize     | r         |                              |
             * 5f         | PUSH0             | 0 r       |                              |
             * 81         | DUP2              | r 0 r     |                              |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
             * 5f         | PUSH0             | 0 o r 0 r |                              |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
             * f3         | RETURN            |           | [0..runSize): runtime code   |
             * --------------------------------------------------------------------------|
             * RUNTIME (45 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode  | Mnemonic       | Stack                  | Memory                |
             * --------------------------------------------------------------------------|
             *                                                                           |
             * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
             * 5f      | PUSH0          | 0                      |                       |
             * 5f      | PUSH0          | 0 0                    |                       |
             *                                                                           |
             * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0                |                       |
             * 5f      | PUSH0          | 0 cds 0 0              |                       |
             * 5f      | PUSH0          | 0 0 cds 0 0            |                       |
             * 37      | CALLDATACOPY   | 0 0                    | [0..cds): calldata    |
             *                                                                           |
             * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0                | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 cds 0 0              | [0..cds): calldata    |
             * 73 addr | PUSH20 addr    | addr 0 cds 0 0         | [0..cds): calldata    |
             * 5a      | GAS            | gas addr 0 cds 0 0     | [0..cds): calldata    |
             * f4      | DELEGATECALL   | success                | [0..cds): calldata    |
             *                                                                           |
             * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds success            | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 rds success          | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 0 rds success        | [0..cds): calldata    |
             * 3e      | RETURNDATACOPY | success                | [0..rds): returndata  |
             *                                                                           |
             * 60 0x29 | PUSH1 0x29     | 0x29 success           | [0..rds): returndata  |
             * 57      | JUMPI          |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
             * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
             * fd      | REVERT         |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b      | JUMPDEST       |                        | [0..rds): returndata  |
             * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
             * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
             * f3      | RETURN         |                        | [0..rds): returndata  |
             * --------------------------------------------------------------------------+
             */
            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            instance := create(value, 0x0e, 0x36)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
    function cloneDeterministic_PUSH0(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = cloneDeterministic_PUSH0(0, implementation, salt);
    }

    /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
    /// Deposits `value` ETH during deployment.
    function cloneDeterministic_PUSH0(uint256 value, address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            instance := create2(value, 0x0e, 0x36, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the PUSH0 clone of `implementation`.
    function initCode_PUSH0(address implementation) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16
            mstore(add(c, 0x26), implementation) // 20
            mstore(add(c, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            mstore(c, 0x36) // Store the length.
            mstore(0x40, add(c, 0x60)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`.
    function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            hash := keccak256(0x0e, 0x36)
            mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the address of the PUSH0 clone of `implementation`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddress_PUSH0(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHash_PUSH0(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*           CLONES WITH IMMUTABLE ARGS OPERATIONS            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`.
    function clone(address implementation, bytes memory args) internal returns (address instance) {
        instance = clone(0, implementation, args);
    }

    /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`.
    /// Deposits `value` ETH during deployment.
    function clone(uint256 value, address implementation, bytes memory args)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * ---------------------------------------------------------------------------+
             * CREATION (10 bytes)                                                        |
             * ---------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                        |
             * ---------------------------------------------------------------------------|
             * 61 runSize | PUSH2 runSize     | r         |                               |
             * 3d         | RETURNDATASIZE    | 0 r       |                               |
             * 81         | DUP2              | r 0 r     |                               |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                               |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                               |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code    |
             * f3         | RETURN            |           | [0..runSize): runtime code    |
             * ---------------------------------------------------------------------------|
             * RUNTIME (45 bytes + extraLength)                                           |
             * ---------------------------------------------------------------------------|
             * Opcode   | Mnemonic       | Stack                  | Memory                |
             * ---------------------------------------------------------------------------|
             *                                                                            |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds                    |                       |
             * 3d       | RETURNDATASIZE | 0 cds                  |                       |
             * 3d       | RETURNDATASIZE | 0 0 cds                |                       |
             * 37       | CALLDATACOPY   |                        | [0..cds): calldata    |
             *                                                                            |
             * ::: delegate call to the implementation contract ::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | 0                      | [0..cds): calldata    |
             * 3d       | RETURNDATASIZE | 0 0                    | [0..cds): calldata    |
             * 3d       | RETURNDATASIZE | 0 0 0                  | [0..cds): calldata    |
             * 36       | CALLDATASIZE   | cds 0 0 0              | [0..cds): calldata    |
             * 3d       | RETURNDATASIZE | 0 cds 0 0 0 0          | [0..cds): calldata    |
             * 73 addr  | PUSH20 addr    | addr 0 cds 0 0 0 0     | [0..cds): calldata    |
             * 5a       | GAS            | gas addr 0 cds 0 0 0 0 | [0..cds): calldata    |
             * f4       | DELEGATECALL   | success 0 0            | [0..cds): calldata    |
             *                                                                            |
             * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | rds success 0          | [0..cds): calldata    |
             * 82       | DUP3           | 0 rds success 0         | [0..cds): calldata   |
             * 80       | DUP1           | 0 0 rds success 0      | [0..cds): calldata    |
             * 3e       | RETURNDATACOPY | success 0              | [0..rds): returndata  |
             * 90       | SWAP1          | 0 success              | [0..rds): returndata  |
             * 3d       | RETURNDATASIZE | rds 0 success          | [0..rds): returndata  |
             * 91       | SWAP2          | success 0 rds          | [0..rds): returndata  |
             *                                                                            |
             * 60 0x2b  | PUSH1 0x2b     | 0x2b success 0 rds     | [0..rds): returndata  |
             * 57       | JUMPI          | 0 rds                  | [0..rds): returndata  |
             *                                                                            |
             * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd       | REVERT         |                        | [0..rds): returndata  |
             *                                                                            |
             * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b       | JUMPDEST       | 0 rds                  | [0..rds): returndata  |
             * f3       | RETURN         |                        | [0..rds): returndata  |
             * ---------------------------------------------------------------------------+
             */
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n))
            mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(m, 0x14), implementation)
            mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(0x88, n)))
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`.
            instance := create(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37))
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }
    // 0,0x5e17b14ADd6c386305A32928F985b29bbA34Eff5, hex"01020304"
    /// @dev Deploys a deterministic clone of `implementation`
    /// with immutable arguments encoded in `args` and `salt`.

    function cloneDeterministic(address implementation, bytes memory args, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = cloneDeterministic(0, implementation, args, salt);
    }

    /// @dev Deploys a deterministic clone of `implementation`
    /// with immutable arguments encoded in `args` and `salt`.
    function cloneDeterministic(
        uint256 value,
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n))
            mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(m, 0x14), implementation)
            mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(0x88, n)))
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`.
            instance := create2(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37), salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the initialization code hash of the clone of `implementation`
    /// using immutable arguments encoded in `args`.
    function initCode(address implementation, bytes memory args)
        internal
        pure
        returns (bytes memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x57), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(c, 0x37), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(c, 0x28), implementation)
            mstore(add(c, 0x14), add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(0x88, n)))
            mstore(c, add(0x37, n)) // Store the length.
            mstore(add(c, add(n, 0x57)), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(c, add(n, 0x77))) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the clone of `implementation`
    /// using immutable arguments encoded in `args`.
    function initCodeHash(address implementation, bytes memory args)
        internal
        pure
        returns (bytes32 hash)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(m, 0x43), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(m, 0x14), implementation)
            mstore(m, add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(0x88, n)))
            hash := keccak256(add(m, 0x0c), add(n, 0x37))
        }
    }

    /// @dev Returns the address of the clone of
    /// `implementation` using immutable arguments encoded in `args`, with `salt`, by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddress(
        address implementation,
        bytes memory data,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHash(implementation, data);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /// @dev Equivalent to `argsOnClone(instance, 0, 2 ** 256 - 1)`.
    function argsOnClone(address instance) internal view returns (bytes memory args) {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            mstore(args, sub(extcodesize(instance), 0x2d)) // Store the length.
            extcodecopy(instance, add(args, 0x20), 0x2d, add(mload(args), 0x20))
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `argsOnClone(instance, start, 2 ** 256 - 1)`.
    function argsOnClone(address instance, uint256 start)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            let n := sub(extcodesize(instance), 0x2d)
            extcodecopy(instance, add(args, 0x20), add(start, 0x2d), add(n, 0x20))
            mstore(args, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory.
        }
    }

    /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `instance` MUST be deployed via the clone with immutable args functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `instance` does not have any code.
    function argsOnClone(address instance, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            if iszero(lt(end, 0xffff)) { end := 0xffff }
            let d := mul(sub(end, start), lt(start, end))
            extcodecopy(instance, args, add(start, 0x0d), add(d, 0x20))
            if iszero(and(0xff, mload(add(args, d)))) {
                let n := sub(extcodesize(instance), 0x2d)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(args, d) // Store the length.
            mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(args, 0x40), d)) // Allocate memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              MINIMAL ERC1967 PROXY OPERATIONS              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: The ERC1967 proxy here is intended to be upgraded with UUPS.
    // This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.

    /// @dev Deploys a minimal ERC1967 proxy with `implementation`.
    function deployERC1967(address implementation) internal returns (address instance) {
        instance = deployERC1967(0, implementation);
    }

    /// @dev Deploys a minimal ERC1967 proxy with `implementation`.
    /// Deposits `value` ETH during deployment.
    function deployERC1967(uint256 value, address implementation)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * ---------------------------------------------------------------------------------+
             * CREATION (34 bytes)                                                              |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize  | r                |                                 |
             * 3d         | RETURNDATASIZE | 0 r              |                                 |
             * 81         | DUP2           | r 0 r            |                                 |
             * 60 offset  | PUSH1 offset   | o r 0 r          |                                 |
             * 3d         | RETURNDATASIZE | 0 o r 0 r        |                                 |
             * 39         | CODECOPY       | 0 r              | [0..runSize): runtime code      |
             * 73 impl    | PUSH20 impl    | impl 0 r         | [0..runSize): runtime code      |
             * 60 slotPos | PUSH1 slotPos  | slotPos impl 0 r | [0..runSize): runtime code      |
             * 51         | MLOAD          | slot impl 0 r    | [0..runSize): runtime code      |
             * 55         | SSTORE         | 0 r              | [0..runSize): runtime code      |
             * f3         | RETURN         |                  | [0..runSize): runtime code      |
             * ---------------------------------------------------------------------------------|
             * RUNTIME (61 bytes)                                                               |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             *                                                                                  |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36         | CALLDATASIZE   | cds              |                                 |
             * 3d         | RETURNDATASIZE | 0 cds            |                                 |
             * 3d         | RETURNDATASIZE | 0 0 cds          |                                 |
             * 37         | CALLDATACOPY   |                  | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | 0                |                                 |
             * 3d         | RETURNDATASIZE | 0 0              |                                 |
             * 36         | CALLDATASIZE   | cds 0 0          | [0..calldatasize): calldata     |
             * 3d         | RETURNDATASIZE | 0 cds 0 0        | [0..calldatasize): calldata     |
             * 7f slot    | PUSH32 slot    | s 0 cds 0 0      | [0..calldatasize): calldata     |
             * 54         | SLOAD          | i 0 cds 0 0      | [0..calldatasize): calldata     |
             * 5a         | GAS            | g i 0 cds 0 0    | [0..calldatasize): calldata     |
             * f4         | DELEGATECALL   | succ             | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds succ         | [0..calldatasize): calldata     |
             * 60 0x00    | PUSH1 0x00     | 0 rds succ       | [0..calldatasize): calldata     |
             * 80         | DUP1           | 0 0 rds succ     | [0..calldatasize): calldata     |
             * 3e         | RETURNDATACOPY | succ             | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
             * 60 0x38    | PUSH1 0x38     | dest succ        | [0..returndatasize): returndata |
             * 57         | JUMPI          |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * fd         | REVERT         |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b         | JUMPDEST       |                  | [0..returndatasize): returndata |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * f3         | RETURN         |                  | [0..returndatasize): returndata |
             * ---------------------------------------------------------------------------------+
             */
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x20, 0x6009)
            mstore(0x1e, implementation)
            mstore(0x0a, 0x603d3d8160223d3973)
            instance := create(value, 0x21, 0x5f)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
    function deployDeterministicERC1967(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967(0, implementation, salt);
    }

    /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967(uint256 value, address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x20, 0x6009)
            mstore(0x1e, implementation)
            mstore(0x0a, 0x603d3d8160223d3973)
            instance := create2(value, 0x21, 0x5f, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967(address implementation, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967(0, implementation, salt);
    }

    /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967(uint256 value, address implementation, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x20, 0x6009)
            mstore(0x1e, implementation)
            mstore(0x0a, 0x603d3d8160223d3973)
            // Compute and store the bytecode hash.
            mstore(add(m, 0x35), keccak256(0x21, 0x5f))
            mstore(m, shl(88, address()))
            mstore8(m, 0xff) // Write the prefix.
            mstore(add(m, 0x15), salt)
            instance := keccak256(m, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, 0x21, 0x5f, salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`.
    function initCodeERC1967(address implementation) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x60), 0x3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f300)
            mstore(add(c, 0x40), 0x55f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc)
            mstore(add(c, 0x20), or(shl(24, implementation), 0x600951))
            mstore(add(c, 0x09), 0x603d3d8160223d3973)
            mstore(c, 0x5f) // Store the length.
            mstore(0x40, add(c, 0x80)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`.
    function initCodeHashERC1967(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x20, 0x6009)
            mstore(0x1e, implementation)
            mstore(0x0a, 0x603d3d8160223d3973)
            hash := keccak256(0x21, 0x5f)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the address of the ERC1967 proxy of `implementation`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*    MINIMAL ERC1967 PROXY WITH IMMUTABLE ARGS OPERATIONS    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`.
    function deployERC1967(address implementation, bytes memory args)
        internal
        returns (address instance)
    {
        instance = deployERC1967(0, implementation, args);
    }

    /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`.
    /// Deposits `value` ETH during deployment.
    function deployERC1967(uint256 value, address implementation, bytes memory args)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n))
            mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x16, 0x6009)
            mstore(0x14, implementation)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`.
            mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            instance := create(value, m, add(n, 0x60))
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`.
    function deployDeterministicERC1967(address implementation, bytes memory args, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967(0, implementation, args, salt);
    }

    /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967(
        uint256 value,
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n))
            mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x16, 0x6009)
            mstore(0x14, implementation)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`.
            mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            instance := create2(value, m, add(n, 0x60), salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967(address implementation, bytes memory args, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967(0, implementation, args, salt);
    }

    /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967(
        uint256 value,
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (bool alreadyDeployed, address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n))
            mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x16, 0x6009)
            mstore(0x14, implementation)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`.
            mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, keccak256(m, add(n, 0x60)))
            mstore(0x01, shl(96, address()))
            mstore(0x15, salt)
            instance := keccak256(0x00, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, m, add(n, 0x60), salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation` and `args`.
    function initCodeERC1967(address implementation, bytes memory args)
        internal
        pure
        returns (bytes memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x80), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(c, 0x60), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(add(c, 0x40), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(add(c, 0x20), 0x6009)
            mstore(add(c, 0x1e), implementation)
            mstore(add(c, 0x0a), add(0x61003d3d8160233d3973, shl(56, n)))
            mstore(c, add(n, 0x60)) // Store the length.
            mstore(add(c, add(n, 0x80)), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(c, add(n, 0xa0))) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation` and `args`.
    function initCodeHashERC1967(address implementation, bytes memory args)
        internal
        pure
        returns (bytes32 hash)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(m, 0x60), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
            mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
            mstore(0x16, 0x6009)
            mstore(0x14, implementation)
            mstore(0x00, add(0x61003d3d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            hash := keccak256(m, add(n, 0x60))
        }
    }

    /// @dev Returns the address of the ERC1967 proxy of `implementation`, `args`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967(implementation, args);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967(address instance) internal view returns (bytes memory args) {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            mstore(args, sub(extcodesize(instance), 0x3d)) // Store the length.
            extcodecopy(instance, add(args, 0x20), 0x3d, add(mload(args), 0x20))
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967(address instance, uint256 start)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            let n := sub(extcodesize(instance), 0x3d)
            extcodecopy(instance, add(args, 0x20), add(start, 0x3d), add(n, 0x20))
            mstore(args, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory.
        }
    }

    /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `instance` MUST be deployed via the ERC1967 with immutable args functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `instance` does not have any code.
    function argsOnERC1967(address instance, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            if iszero(lt(end, 0xffff)) { end := 0xffff }
            let d := mul(sub(end, start), lt(start, end))
            extcodecopy(instance, args, add(start, 0x1d), add(d, 0x20))
            if iszero(and(0xff, mload(add(args, d)))) {
                let n := sub(extcodesize(instance), 0x3d)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(args, d) // Store the length.
            mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(args, 0x40), d)) // Allocate memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                 ERC1967I PROXY OPERATIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: This proxy has a special code path that activates if `calldatasize() == 1`.
    // This code path skips the delegatecall and directly returns the `implementation` address.
    // The returned implementation is guaranteed to be valid if the keccak256 of the
    // proxy's code is equal to `ERC1967I_CODE_HASH`.

    /// @dev Deploys a ERC1967I proxy with `implementation`.
    function deployERC1967I(address implementation) internal returns (address instance) {
        instance = deployERC1967I(0, implementation);
    }

    /// @dev Deploys a ERC1967I proxy with `implementation`.
    /// Deposits `value` ETH during deployment.
    function deployERC1967I(uint256 value, address implementation)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * ---------------------------------------------------------------------------------+
             * CREATION (34 bytes)                                                              |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize  | r                |                                 |
             * 3d         | RETURNDATASIZE | 0 r              |                                 |
             * 81         | DUP2           | r 0 r            |                                 |
             * 60 offset  | PUSH1 offset   | o r 0 r          |                                 |
             * 3d         | RETURNDATASIZE | 0 o r 0 r        |                                 |
             * 39         | CODECOPY       | 0 r              | [0..runSize): runtime code      |
             * 73 impl    | PUSH20 impl    | impl 0 r         | [0..runSize): runtime code      |
             * 60 slotPos | PUSH1 slotPos  | slotPos impl 0 r | [0..runSize): runtime code      |
             * 51         | MLOAD          | slot impl 0 r    | [0..runSize): runtime code      |
             * 55         | SSTORE         | 0 r              | [0..runSize): runtime code      |
             * f3         | RETURN         |                  | [0..runSize): runtime code      |
             * ---------------------------------------------------------------------------------|
             * RUNTIME (82 bytes)                                                               |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             *                                                                                  |
             * ::: check calldatasize ::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36         | CALLDATASIZE   | cds              |                                 |
             * 58         | PC             | 1 cds            |                                 |
             * 14         | EQ             | eqs              |                                 |
             * 60 0x43    | PUSH1 0x43     | dest eqs         |                                 |
             * 57         | JUMPI          |                  |                                 |
             *                                                                                  |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36         | CALLDATASIZE   | cds              |                                 |
             * 3d         | RETURNDATASIZE | 0 cds            |                                 |
             * 3d         | RETURNDATASIZE | 0 0 cds          |                                 |
             * 37         | CALLDATACOPY   |                  | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | 0                |                                 |
             * 3d         | RETURNDATASIZE | 0 0              |                                 |
             * 36         | CALLDATASIZE   | cds 0 0          | [0..calldatasize): calldata     |
             * 3d         | RETURNDATASIZE | 0 cds 0 0        | [0..calldatasize): calldata     |
             * 7f slot    | PUSH32 slot    | s 0 cds 0 0      | [0..calldatasize): calldata     |
             * 54         | SLOAD          | i 0 cds 0 0      | [0..calldatasize): calldata     |
             * 5a         | GAS            | g i 0 cds 0 0    | [0..calldatasize): calldata     |
             * f4         | DELEGATECALL   | succ             | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds succ         | [0..calldatasize): calldata     |
             * 60 0x00    | PUSH1 0x00     | 0 rds succ       | [0..calldatasize): calldata     |
             * 80         | DUP1           | 0 0 rds succ     | [0..calldatasize): calldata     |
             * 3e         | RETURNDATACOPY | succ             | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
             * 60 0x3E    | PUSH1 0x3E     | dest succ        | [0..returndatasize): returndata |
             * 57         | JUMPI          |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * fd         | REVERT         |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b         | JUMPDEST       |                  | [0..returndatasize): returndata |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * f3         | RETURN         |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: implementation , return :::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b         | JUMPDEST       |                  |                                 |
             * 60 0x20    | PUSH1 0x20     | 32               |                                 |
             * 60 0x0F    | PUSH1 0x0F     | o 32             |                                 |
             * 3d         | RETURNDATASIZE | 0 o 32           |                                 |
             * 39         | CODECOPY       |                  | [0..32): implementation slot    |
             * 3d         | RETURNDATASIZE | 0                | [0..32): implementation slot    |
             * 51         | MLOAD          | slot             | [0..32): implementation slot    |
             * 54         | SLOAD          | impl             | [0..32): implementation slot    |
             * 3d         | RETURNDATASIZE | 0 impl           | [0..32): implementation slot    |
             * 52         | MSTORE         |                  | [0..32): implementation address |
             * 59         | MSIZE          | 32               | [0..32): implementation address |
             * 3d         | RETURNDATASIZE | 0 32             | [0..32): implementation address |
             * f3         | RETURN         |                  | [0..32): implementation address |
             * ---------------------------------------------------------------------------------+
             */
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
            instance := create(value, 0x0c, 0x74)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`.
    function deployDeterministicERC1967I(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967I(0, implementation, salt);
    }

    /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967I(uint256 value, address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
            instance := create2(value, 0x0c, 0x74, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967I(address implementation, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967I(0, implementation, salt);
    }

    /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967I(uint256 value, address implementation, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
            // Compute and store the bytecode hash.
            mstore(add(m, 0x35), keccak256(0x0c, 0x74))
            mstore(m, shl(88, address()))
            mstore8(m, 0xff) // Write the prefix.
            mstore(add(m, 0x15), salt)
            instance := keccak256(m, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, 0x0c, 0x74, salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the initialization code of the ERC1967I proxy of `implementation`.
    function initCodeERC1967I(address implementation) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x74), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(c, 0x54), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(c, 0x34), 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(add(c, 0x1d), implementation)
            mstore(add(c, 0x09), 0x60523d8160223d3973)
            mstore(add(c, 0x94), 0)
            mstore(c, 0x74) // Store the length.
            mstore(0x40, add(c, 0xa0)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation`.
    function initCodeHashERC1967I(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation))))
            hash := keccak256(0x0c, 0x74)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the address of the ERC1967I proxy of `implementation`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967I(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967I(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*       ERC1967I PROXY WITH IMMUTABLE ARGS OPERATIONS        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`.
    function deployERC1967I(address implementation, bytes memory args) internal returns (address) {
        return deployERC1967I(0, implementation, args);
    }

    /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`.
    /// Deposits `value` ETH during deployment.
    function deployERC1967I(uint256 value, address implementation, bytes memory args)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n))

            mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(add(m, 0x14), implementation)
            mstore(m, add(0xfe6100523d8160233d3973, shl(56, n)))

            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            instance := create(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n))
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic ERC1967I proxy with `implementation`, `args`, and `salt`.
    function deployDeterministicERC1967I(address implementation, bytes memory args, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967I(0, implementation, args, salt);
    }

    /// @dev Deploys a deterministic ERC1967I proxy with `implementation`,`args`,  and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967I(
        uint256 value,
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n))

            mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(add(m, 0x14), implementation)
            mstore(m, add(0xfe6100523d8160233d3973, shl(56, n)))

            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            instance := create2(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n), salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Creates a deterministic ERC1967I proxy with `implementation`, `args` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967I(address implementation, bytes memory args, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967I(0, implementation, args, salt);
    }

    /// @dev Creates a deterministic ERC1967I proxy with `implementation`,`args` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967I(
        uint256 value,
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (bool alreadyDeployed, address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x75), n))
            mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x16, 0x600f)
            mstore(0x14, implementation)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            mstore(gt(n, 0xffad), add(0xfe6100523d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, keccak256(m, add(n, 0x75)))
            mstore(0x01, shl(96, address()))
            mstore(0x15, salt)
            instance := keccak256(0x00, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, m, add(0x75, n), salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the ERC1967I proxy of `implementation`and `args`.
    function initCodeERC1967I(address implementation, bytes memory args)
        internal
        pure
        returns (bytes memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i)))
            }

            mstore(add(c, 0x75), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(c, 0x55), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(c, 0x35), 0x600f5155f3365814604357363d3d373d3d363d7f360894)
            mstore(add(c, 0x1e), implementation)
            mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n)))
            mstore(add(c, add(n, 0x95)), 0)
            mstore(c, add(0x75, n)) // Store the length.
            mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation` and `args.
    function initCodeHashERC1967I(address implementation, bytes memory args)
        internal
        pure
        returns (bytes32 hash)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad))

            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(m, 0x75), i), mload(add(add(args, 0x20), i)))
            }

            mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3)
            mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4)
            mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894)
            mstore(0x16, 0x600f)
            mstore(0x14, implementation)
            mstore(0x00, add(0x6100523d8160233d3973, shl(56, n)))
            mstore(m, mload(0x16))
            hash := keccak256(m, add(0x75, n))
        }
    }

    /// @dev Returns the address of the ERC1967I proxy of `implementation`, 'args` with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967I(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967I(implementation, args);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967I(address instance) internal view returns (bytes memory args) {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            mstore(args, sub(extcodesize(instance), 0x52)) // Store the length.
            extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20))
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967I(address instance, uint256 start)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            let n := sub(extcodesize(instance), 0x52)
            extcodecopy(instance, add(args, 0x20), add(start, 0x52), add(n, 0x20))
            mstore(args, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `instance` MUST be deployed via the ERC1967 with immutable args functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `instance` does not have any code.
    function argsOnERC1967I(address instance, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            if iszero(lt(end, 0xffff)) { end := 0xffff }
            let d := mul(sub(end, start), lt(start, end))
            extcodecopy(instance, args, add(start, 0x32), add(d, 0x20))
            if iszero(and(0xff, mload(add(args, d)))) {
                let n := sub(extcodesize(instance), 0x52)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(args, d) // Store the length.
            mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(args, 0x40), d)) // Allocate memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            CONSTANT ERC1967 BOOTSTRAP OPERATIONS           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: This enables an ERC1967 proxy to be deployed at a deterministic address
    // independent of the implementation:
    // ```
    //     address bootstrap = LibClone.constantERC1967Bootstrap();
    //     address instance = LibClone.deployDeterministicERC1967(0, bootstrap, salt);
    //     LibClone.bootstrapConstantERC1967(bootstrap, implementation);
    // ```

    /// @dev Deploys the constant ERC1967 bootstrap if it has not been deployed.
    function constantERC1967Bootstrap() internal returns (address bootstrap) {
        bootstrap = constantERC1967BootstrapAddress();
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(extcodesize(bootstrap)) {
                mstore(0x20, 0x0894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55)
                mstore(0x00, 0x60258060093d393df358357f36)
                if iszero(create2(0, 0x13, 0x2e, 0)) {
                    mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract.
    function constantERC1967BootstrapAddress() internal view returns (address bootstrap) {
        bytes32 hash = 0xfe1a42b9c571a6a8c083c94ac67b9cfd74e2582923426aa3b762e3431d717cd1;
        bootstrap = predictDeterministicAddress(hash, bytes32(0), address(this));
    }

    /// @dev Replaces the implementation at `instance`.
    function bootstrapERC1967(address instance, address implementation) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, shr(96, shl(96, implementation)))
            if iszero(call(gas(), instance, 0, 0x00, 0x20, codesize(), 0x00)) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          MINIMAL ERC1967 BEACON PROXY OPERATIONS           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: If you use this proxy, you MUST make sure that the beacon is a
    // valid ERC1967 beacon. This means that the beacon must always return a valid
    // address upon a staticcall to `implementation()`, given sufficient gas.
    // For performance, the deployment operations and the proxy assumes that the
    // beacon is always valid and will NOT validate it.

    /// @dev Deploys a minimal ERC1967 beacon proxy.
    function deployERC1967BeaconProxy(address beacon) internal returns (address instance) {
        instance = deployERC1967BeaconProxy(0, beacon);
    }

    /// @dev Deploys a minimal ERC1967 beacon proxy.
    /// Deposits `value` ETH during deployment.
    function deployERC1967BeaconProxy(uint256 value, address beacon)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * ---------------------------------------------------------------------------------+
             * CREATION (34 bytes)                                                              |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize  | r                |                                 |
             * 3d         | RETURNDATASIZE | 0 r              |                                 |
             * 81         | DUP2           | r 0 r            |                                 |
             * 60 offset  | PUSH1 offset   | o r 0 r          |                                 |
             * 3d         | RETURNDATASIZE | 0 o r 0 r        |                                 |
             * 39         | CODECOPY       | 0 r              | [0..runSize): runtime code      |
             * 73 beac    | PUSH20 beac    | beac 0 r         | [0..runSize): runtime code      |
             * 60 slotPos | PUSH1 slotPos  | slotPos beac 0 r | [0..runSize): runtime code      |
             * 51         | MLOAD          | slot beac 0 r    | [0..runSize): runtime code      |
             * 55         | SSTORE         | 0 r              | [0..runSize): runtime code      |
             * f3         | RETURN         |                  | [0..runSize): runtime code      |
             * ---------------------------------------------------------------------------------|
             * RUNTIME (82 bytes)                                                               |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             *                                                                                  |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36         | CALLDATASIZE   | cds              |                                 |
             * 3d         | RETURNDATASIZE | 0 cds            |                                 |
             * 3d         | RETURNDATASIZE | 0 0 cds          |                                 |
             * 37         | CALLDATACOPY   |                  | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | 0                |                                 |
             * 3d         | RETURNDATASIZE | 0 0              |                                 |
             * 36         | CALLDATASIZE   | cds 0 0          | [0..calldatasize): calldata     |
             * 3d         | RETURNDATASIZE | 0 cds 0 0        | [0..calldatasize): calldata     |
             *                                                                                  |
             * ~~~~~~~ beacon staticcall sub procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 60 0x20       | PUSH1 0x20       | 32                          |                 |
             * 36            | CALLDATASIZE     | cds 32                      |                 |
             * 60 0x04       | PUSH1 0x04       | 4 cds 32                    |                 |
             * 36            | CALLDATASIZE     | cds 4 cds 32                |                 |
             * 63 0x5c60da1b | PUSH4 0x5c60da1b | 0x5c60da1b cds 4 cds 32     |                 |
             * 60 0xe0       | PUSH1 0xe0       | 224 0x5c60da1b cds 4 cds 32 |                 |
             * 1b            | SHL              | sel cds 4 cds 32            |                 |
             * 36            | CALLDATASIZE     | cds sel cds 4 cds 32        |                 |
             * 52            | MSTORE           | cds 4 cds 32                | sel             |
             * 7f slot       | PUSH32 slot      | s cds 4 cds 32              | sel             |
             * 54            | SLOAD            | beac cds 4 cds 32           | sel             |
             * 5a            | GAS              | g beac cds 4 cds 32         | sel             |
             * fa            | STATICCALL       | succ                        | impl            |
             * 50            | POP              |                             | impl            |
             * 36            | CALLDATASIZE     | cds                         | impl            |
             * 51            | MLOAD            | impl                        | impl            |
             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 5a         | GAS            | g impl 0 cds 0 0 | [0..calldatasize): calldata     |
             * f4         | DELEGATECALL   | succ             | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds succ         | [0..calldatasize): calldata     |
             * 60 0x00    | PUSH1 0x00     | 0 rds succ       | [0..calldatasize): calldata     |
             * 80         | DUP1           | 0 0 rds succ     | [0..calldatasize): calldata     |
             * 3e         | RETURNDATACOPY | succ             | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
             * 60 0x4d    | PUSH1 0x4d     | dest succ        | [0..returndatasize): returndata |
             * 57         | JUMPI          |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * fd         | REVERT         |                  | [0..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b         | JUMPDEST       |                  | [0..returndatasize): returndata |
             * 3d         | RETURNDATASIZE | rds              | [0..returndatasize): returndata |
             * 60 0x00    | PUSH1 0x00     | 0 rds            | [0..returndatasize): returndata |
             * f3         | RETURN         |                  | [0..returndatasize): returndata |
             * ---------------------------------------------------------------------------------+
             */
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon))))
            instance := create(value, 0x0c, 0x74)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`.
    function deployDeterministicERC1967BeaconProxy(address beacon, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967BeaconProxy(0, beacon, salt);
    }

    /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967BeaconProxy(uint256 value, address beacon, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon))))
            instance := create2(value, 0x0c, 0x74, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967BeaconProxy(address beacon, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967BeaconProxy(0, beacon, salt);
    }

    /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967BeaconProxy(uint256 value, address beacon, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon))))
            // Compute and store the bytecode hash.
            mstore(add(m, 0x35), keccak256(0x0c, 0x74))
            mstore(m, shl(88, address()))
            mstore8(m, 0xff) // Write the prefix.
            mstore(add(m, 0x15), salt)
            instance := keccak256(m, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, 0x0c, 0x74, salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy.
    function initCodeERC1967BeaconProxy(address beacon) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x74), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(c, 0x54), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(c, 0x34), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(c, 0x1d), beacon)
            mstore(add(c, 0x09), 0x60523d8160223d3973)
            mstore(add(c, 0x94), 0)
            mstore(c, 0x74) // Store the length.
            mstore(0x40, add(c, 0xa0)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy.
    function initCodeHashERC1967BeaconProxy(address beacon) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon))))
            hash := keccak256(0x0c, 0x74)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the address of the ERC1967 beacon proxy, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967BeaconProxy(
        address beacon,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967BeaconProxy(beacon);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*    ERC1967 BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a minimal ERC1967 beacon proxy with `args`.
    function deployERC1967BeaconProxy(address beacon, bytes memory args)
        internal
        returns (address instance)
    {
        instance = deployERC1967BeaconProxy(0, beacon, args);
    }

    /// @dev Deploys a minimal ERC1967 beacon proxy with `args`.
    /// Deposits `value` ETH during deployment.
    function deployERC1967BeaconProxy(uint256 value, address beacon, bytes memory args)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n))
            mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n)))
            instance := create(value, add(m, 0x16), add(n, 0x75))
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`.
    function deployDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967BeaconProxy(0, beacon, args, salt);
    }

    /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967BeaconProxy(
        uint256 value,
        address beacon,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n))
            mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n)))
            instance := create2(value, add(m, 0x16), add(n, 0x75), salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967BeaconProxy(0, beacon, args, salt);
    }

    /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967BeaconProxy(
        uint256 value,
        address beacon,
        bytes memory args,
        bytes32 salt
    ) internal returns (bool alreadyDeployed, address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n))
            mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n)))
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, keccak256(add(m, 0x16), add(n, 0x75)))
            mstore(0x01, shl(96, address()))
            mstore(0x15, salt)
            instance := keccak256(0x00, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, add(m, 0x16), add(n, 0x75), salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy.
    function initCodeERC1967BeaconProxy(address beacon, bytes memory args)
        internal
        pure
        returns (bytes memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(c, 0x75), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(c, 0x55), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(c, 0x35), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(c, 0x1e), beacon)
            mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n)))
            mstore(c, add(n, 0x75)) // Store the length.
            mstore(add(c, add(n, 0x95)), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy with `args`.
    function initCodeHashERC1967BeaconProxy(address beacon, bytes memory args)
        internal
        pure
        returns (bytes32 hash)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(m, 0x8b), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3)
            mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c)
            mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da)
            mstore(add(m, 0x14), beacon)
            mstore(m, add(0x6100523d8160233d3973, shl(56, n)))
            hash := keccak256(add(m, 0x16), add(n, 0x75))
        }
    }

    /// @dev Returns the address of the ERC1967 beacon proxy with `args`, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967BeaconProxy(
        address beacon,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967BeaconProxy(beacon, args);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967BeaconProxy(address instance) internal view returns (bytes memory args) {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            mstore(args, sub(extcodesize(instance), 0x52)) // Store the length.
            extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20))
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967BeaconProxy(address instance, uint256 start)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            let n := sub(extcodesize(instance), 0x52)
            extcodecopy(instance, add(args, 0x20), add(start, 0x52), add(n, 0x20))
            mstore(args, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory.
        }
    }

    /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `instance` MUST be deployed via the ERC1967 beacon proxy with immutable args functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `instance` does not have any code.
    function argsOnERC1967BeaconProxy(address instance, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            if iszero(lt(end, 0xffff)) { end := 0xffff }
            let d := mul(sub(end, start), lt(start, end))
            extcodecopy(instance, args, add(start, 0x32), add(d, 0x20))
            if iszero(and(0xff, mload(add(args, d)))) {
                let n := sub(extcodesize(instance), 0x52)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(args, d) // Store the length.
            mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(args, 0x40), d)) // Allocate memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              ERC1967I BEACON PROXY OPERATIONS              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: This proxy has a special code path that activates if `calldatasize() == 1`.
    // This code path skips the delegatecall and directly returns the `implementation` address.
    // The returned implementation is guaranteed to be valid if the keccak256 of the
    // proxy's code is equal to `ERC1967_BEACON_PROXY_CODE_HASH`.
    //
    // If you use this proxy, you MUST make sure that the beacon is a
    // valid ERC1967 beacon. This means that the beacon must always return a valid
    // address upon a staticcall to `implementation()`, given sufficient gas.
    // For performance, the deployment operations and the proxy assumes that the
    // beacon is always valid and will NOT validate it.

    /// @dev Deploys a ERC1967I beacon proxy.
    function deployERC1967IBeaconProxy(address beacon) internal returns (address instance) {
        instance = deployERC1967IBeaconProxy(0, beacon);
    }

    /// @dev Deploys a ERC1967I beacon proxy.
    /// Deposits `value` ETH during deployment.
    function deployERC1967IBeaconProxy(uint256 value, address beacon)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * ---------------------------------------------------------------------------------+
             * CREATION (34 bytes)                                                              |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize  | r                |                                 |
             * 3d         | RETURNDATASIZE | 0 r              |                                 |
             * 81         | DUP2           | r 0 r            |                                 |
             * 60 offset  | PUSH1 offset   | o r 0 r          |                                 |
             * 3d         | RETURNDATASIZE | 0 o r 0 r        |                                 |
             * 39         | CODECOPY       | 0 r              | [0..runSize): runtime code      |
             * 73 beac    | PUSH20 beac    | beac 0 r         | [0..runSize): runtime code      |
             * 60 slotPos | PUSH1 slotPos  | slotPos beac 0 r | [0..runSize): runtime code      |
             * 51         | MLOAD          | slot beac 0 r    | [0..runSize): runtime code      |
             * 55         | SSTORE         | 0 r              | [0..runSize): runtime code      |
             * f3         | RETURN         |                  | [0..runSize): runtime code      |
             * ---------------------------------------------------------------------------------|
             * RUNTIME (87 bytes)                                                               |
             * ---------------------------------------------------------------------------------|
             * Opcode     | Mnemonic       | Stack            | Memory                          |
             * ---------------------------------------------------------------------------------|
             *                                                                                  |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36         | CALLDATASIZE   | cds              |                                 |
             * 3d         | RETURNDATASIZE | 0 cds            |                                 |
             * 3d         | RETURNDATASIZE | 0 0 cds          |                                 |
             * 37         | CALLDATACOPY   |                  | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | 0                |                                 |
             * 3d         | RETURNDATASIZE | 0 0              |                                 |
             * 36         | CALLDATASIZE   | cds 0 0          | [0..calldatasize): calldata     |
             * 3d         | RETURNDATASIZE | 0 cds 0 0        | [0..calldatasize): calldata     |
             *                                                                                  |
             * ~~~~~~~ beacon staticcall sub procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 60 0x20       | PUSH1 0x20       | 32                          |                 |
             * 36            | CALLDATASIZE     | cds 32                      |                 |
             * 60 0x04       | PUSH1 0x04       | 4 cds 32                    |                 |
             * 36            | CALLDATASIZE     | cds 4 cds 32                |                 |
             * 63 0x5c60da1b | PUSH4 0x5c60da1b | 0x5c60da1b cds 4 cds 32     |                 |
             * 60 0xe0       | PUSH1 0xe0       | 224 0x5c60da1b cds 4 cds 32 |                 |
             * 1b            | SHL              | sel cds 4 cds 32            |                 |
             * 36            | CALLDATASIZE     | cds sel cds 4 cds 32        |                 |
             * 52            | MSTORE           | cds 4 cds 32                | sel             |
             * 7f slot       | PUSH32 slot      | s cds 4 cds 32              | sel             |
             * 54            | SLOAD            | beac cds 4 cds 32           | sel             |
             * 5a            | GAS              | g beac cds 4 cds 32         | sel             |
             * fa            | STATICCALL       | succ                        | impl            |
             * ~~~~~~ check calldatasize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 36            | CALLDATASIZE     | cds succ                    |                 |
             * 14            | EQ               |                             | impl            |
             * 60 0x52       | PUSH1 0x52       |                             | impl            |
             * 57            | JUMPI            |                             | impl            |
             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 36            | CALLDATASIZE     | cds                         | impl            |
             * 51            | MLOAD            | impl                        | impl            |
             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
             * 5a         | GAS            | g impl 0 cds 0 0 | [0..calldatasize): calldata     |
             * f4         | DELEGATECALL   | succ             | [0..calldatasize): calldata     |
             *                                                                                  |
             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds succ         | [0..calldatasize): calldata     |
             * 60 0x00    | PUSH1 0x00     | 0 rds succ       | [0..calldatasize): calldata     |
             * 60 0x01    | PUSH1 0x01     | 1 0 rds succ     | [0..calldatasize): calldata     |
             * 3e         | RETURNDATACOPY | succ             | [1..returndatasize): returndata |
             *                                                                                  |
             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
             * 60 0x52    | PUSH1 0x52     | dest succ        | [1..returndatasize): returndata |
             * 57         | JUMPI          |                  | [1..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d         | RETURNDATASIZE | rds              | [1..returndatasize): returndata |
             * 60 0x01    | PUSH1 0x01     | 1 rds            | [1..returndatasize): returndata |
             * fd         | REVERT         |                  | [1..returndatasize): returndata |
             *                                                                                  |
             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b         | JUMPDEST       |                  | [1..returndatasize): returndata |
             * 3d         | RETURNDATASIZE | rds              | [1..returndatasize): returndata |
             * 60 0x01    | PUSH1 0x01     | 1 rds            | [1..returndatasize): returndata |
             * f3         | RETURN         |                  | [1..returndatasize): returndata |
             * ---------------------------------------------------------------------------------+
             */
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon))))
            instance := create(value, 0x07, 0x79)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Deploys a deterministic ERC1967I beacon proxy with `salt`.
    function deployDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967IBeaconProxy(0, beacon, salt);
    }

    /// @dev Deploys a deterministic ERC1967I beacon proxy with `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967IBeaconProxy(uint256 value, address beacon, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon))))
            instance := create2(value, 0x07, 0x79, salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Creates a deterministic ERC1967I beacon proxy with `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967IBeaconProxy(0, beacon, salt);
    }

    /// @dev Creates a deterministic ERC1967I beacon proxy with `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967IBeaconProxy(uint256 value, address beacon, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon))))
            // Compute and store the bytecode hash.
            mstore(add(m, 0x35), keccak256(0x07, 0x79))
            mstore(m, shl(88, address()))
            mstore8(m, 0xff) // Write the prefix.
            mstore(add(m, 0x15), salt)
            instance := keccak256(m, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, 0x07, 0x79, salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the initialization code of the ERC1967I beacon proxy.
    function initCodeERC1967IBeaconProxy(address beacon) internal pure returns (bytes memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            mstore(add(c, 0x79), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(c, 0x59), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(c, 0x39), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(c, 0x1d), beacon)
            mstore(add(c, 0x09), 0x60573d8160223d3973)
            mstore(add(c, 0x99), 0)
            mstore(c, 0x79) // Store the length.
            mstore(0x40, add(c, 0xa0)) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the ERC1967I beacon proxy.
    function initCodeHashERC1967IBeaconProxy(address beacon) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon))))
            hash := keccak256(0x07, 0x79)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero slot.
        }
    }

    /// @dev Returns the address of the ERC1967I beacon proxy, with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967IBeaconProxy(
        address beacon,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*    ERC1967I BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a ERC1967I beacon proxy with `args.
    function deployERC1967IBeaconProxy(address beacon, bytes memory args)
        internal
        returns (address instance)
    {
        instance = deployERC1967IBeaconProxy(0, beacon, args);
    }

    /// @dev Deploys a ERC1967I beacon proxy with `args.
    /// Deposits `value` ETH during deployment.
    function deployERC1967IBeaconProxy(uint256 value, address beacon, bytes memory args)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n))
            mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`.
            mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n)))
            instance := create(value, add(m, 0x16), add(n, 0x7a))
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`.
    function deployDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt)
        internal
        returns (address instance)
    {
        instance = deployDeterministicERC1967IBeaconProxy(0, beacon, args, salt);
    }

    /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    function deployDeterministicERC1967IBeaconProxy(
        uint256 value,
        address beacon,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n))
            mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`.
            mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n)))
            instance := create2(value, add(m, 0x16), add(n, 0x7a), salt)
            if iszero(instance) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Creates a deterministic ERC1967I beacon proxy with `args` and `salt`.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt)
        internal
        returns (bool alreadyDeployed, address instance)
    {
        return createDeterministicERC1967IBeaconProxy(0, beacon, args, salt);
    }

    /// @dev Creates a deterministic ERC1967I beacon proxy with `args` and `salt`.
    /// Deposits `value` ETH during deployment.
    /// Note: This method is intended for use in ERC4337 factories,
    /// which are expected to NOT revert if the proxy is already deployed.
    function createDeterministicERC1967IBeaconProxy(
        uint256 value,
        address beacon,
        bytes memory args,
        bytes32 salt
    ) internal returns (bool alreadyDeployed, address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let n := mload(args)
            pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n))
            mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(m, 0x14), beacon)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`.
            mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n)))
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, keccak256(add(m, 0x16), add(n, 0x7a)))
            mstore(0x01, shl(96, address()))
            mstore(0x15, salt)
            instance := keccak256(0x00, 0x55)
            for {} 1 {} {
                if iszero(extcodesize(instance)) {
                    instance := create2(value, add(m, 0x16), add(n, 0x7a), salt)
                    if iszero(instance) {
                        mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                        revert(0x1c, 0x04)
                    }
                    break
                }
                alreadyDeployed := 1
                if iszero(value) { break }
                if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
                break
            }
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the initialization code of the ERC1967I beacon proxy with `args`.
    function initCodeERC1967IBeaconProxy(address beacon, bytes memory args)
        internal
        pure
        returns (bytes memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            c := mload(0x40)
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x9a), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(c, 0x7a), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(c, 0x5a), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(c, 0x3a), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(c, 0x1e), beacon)
            mstore(add(c, 0x0a), add(0x6100573d8160233d3973, shl(56, n)))
            mstore(add(c, add(n, 0x9a)), 0)
            mstore(c, add(n, 0x7a)) // Store the length.
            mstore(0x40, add(c, add(n, 0xba))) // Allocate memory.
        }
    }

    /// @dev Returns the initialization code hash of the ERC1967I beacon proxy with `args`.
    function initCodeHashERC1967IBeaconProxy(address beacon, bytes memory args)
        internal
        pure
        returns (bytes32 hash)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let c := mload(0x40) // Cache the free memory pointer.
            let n := mload(args)
            // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8))
            for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
                mstore(add(add(c, 0x90), i), mload(add(add(args, 0x20), i)))
            }
            mstore(add(c, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3)
            mstore(add(c, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513)
            mstore(add(c, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36)
            mstore(add(c, 0x14), beacon)
            mstore(c, add(0x6100573d8160233d3973, shl(56, n)))
            hash := keccak256(add(c, 0x16), add(n, 0x7a))
        }
    }

    /// @dev Returns the address of the ERC1967I beacon proxy, with  `args` and salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddressERC1967IBeaconProxy(
        address beacon,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon, args);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967IBeaconProxy(address instance)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            mstore(args, sub(extcodesize(instance), 0x57)) // Store the length.
            extcodecopy(instance, add(args, 0x20), 0x57, add(mload(args), 0x20))
            mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`.
    function argsOnERC1967IBeaconProxy(address instance, uint256 start)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            let n := sub(extcodesize(instance), 0x57)
            extcodecopy(instance, add(args, 0x20), add(start, 0x57), add(n, 0x20))
            mstore(args, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory.
        }
    }

    /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `instance` MUST be deployed via the ERC1967I beacon proxy with immutable args functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `instance` does not have any code.
    function argsOnERC1967IBeaconProxy(address instance, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory args)
    {
        /// @solidity memory-safe-assembly
        assembly {
            args := mload(0x40)
            if iszero(lt(end, 0xffff)) { end := 0xffff }
            let d := mul(sub(end, start), lt(start, end))
            extcodecopy(instance, args, add(start, 0x37), add(d, 0x20))
            if iszero(and(0xff, mload(add(args, d)))) {
                let n := sub(extcodesize(instance), 0x57)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(args, d) // Store the length.
            mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(args, 0x40), d)) // Allocate memory.
        }
    }

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

    /// @dev Returns `address(0)` if the implementation address cannot be determined.
    function implementationOf(address instance) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            for { extcodecopy(instance, 0x00, 0x00, 0x57) } 1 {} {
                if mload(0x2d) {
                    // ERC1967I and ERC1967IBeaconProxy detection.
                    if or(
                        eq(keccak256(0x00, 0x52), ERC1967I_CODE_HASH),
                        eq(keccak256(0x00, 0x57), ERC1967I_BEACON_PROXY_CODE_HASH)
                    ) {
                        pop(staticcall(gas(), instance, 0x00, 0x01, 0x00, 0x20))
                        result := mload(0x0c)
                        break
                    }
                }
                // 0age clone detection.
                result := mload(0x0b)
                codecopy(0x0b, codesize(), 0x14) // Zeroize the 20 bytes for the address.
                if iszero(xor(keccak256(0x00, 0x2c), CLONE_CODE_HASH)) { break }
                mstore(0x0b, result) // Restore the zeroized memory.
                // CWIA detection.
                result := mload(0x0a)
                codecopy(0x0a, codesize(), 0x14) // Zeroize the 20 bytes for the address.
                if iszero(xor(keccak256(0x00, 0x2d), CWIA_CODE_HASH)) { break }
                mstore(0x0a, result) // Restore the zeroized memory.
                // PUSH0 clone detection.
                result := mload(0x09)
                codecopy(0x09, codesize(), 0x14) // Zeroize the 20 bytes for the address.
                result := shr(xor(keccak256(0x00, 0x2d), PUSH0_CLONE_CODE_HASH), result)
                break
            }
            result := shr(96, result)
            mstore(0x37, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the address when a contract with initialization code hash,
    /// `hash`, is deployed with `salt`, by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Requires that `salt` starts with either the zero address or `by`.
    function checkStartsWith(bytes32 salt, address by) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // If the salt does not start with the zero address or `by`.
            if iszero(or(iszero(shr(96, salt)), eq(shr(96, shl(96, by)), shr(96, salt)))) {
                mstore(0x00, 0x0c4549ef) // `SaltDoesNotStartWith()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {
    IModularAccount, ValidationConfig
} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {ModularAccountBase} from "./ModularAccountBase.sol";

/// @title Modular Account
/// @author Alchemy
/// @notice This contract allows initializing with a validation config (of a validation module) to be installed on
/// the account.
contract ModularAccount is ModularAccountBase {
    constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
        ModularAccountBase(entryPoint, executionInstallDelegate)
    {}

    /// @notice Initializes the account with a validation function.
    /// @dev This function is only callable once.
    function initializeWithValidation(
        ValidationConfig validationConfig,
        bytes4[] calldata selectors,
        bytes calldata installData,
        bytes[] calldata hooks
    ) external virtual initializer {
        _installValidation(validationConfig, selectors, installData, hooks);
    }

    /// @inheritdoc IModularAccount
    function accountId() external pure override returns (string memory) {
        return "alchemy.modular-account.2.0.0";
    }

    /// @dev Overrides ModularAccountView.
    function _isNativeFunction(uint32 selector) internal pure override returns (bool) {
        return super._isNativeFunction(selector) || selector == uint32(this.initializeWithValidation.selector);
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {LibClone} from "solady/utils/LibClone.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";

/// @title Semi-Modular Account Bytecode
/// @author Alchemy
/// @notice An implementation of a semi-modular account which reads the signer from proxy bytecode if it is not
/// disabled and zero in storage.
/// @dev Inherits SemiModularAccountBase. This account requires that its proxy is compliant with Solady's LibClone
/// ERC1967WithImmutableArgs bytecode with a bytecode-appended address (should be encodePacked) to be used as the
/// fallback signer.
contract SemiModularAccountBytecode is SemiModularAccountBase {
    constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
        SemiModularAccountBase(entryPoint, executionInstallDelegate)
    {}

    /// @inheritdoc IModularAccount
    function accountId() external pure override returns (string memory) {
        return "alchemy.sma-bytecode.1.0.0";
    }

    /// @dev If the fallback signer is set in storage, we ignore the bytecode signer.
    function _retrieveFallbackSignerUnchecked(SemiModularAccountStorage storage _storage)
        internal
        view
        override
        returns (address)
    {
        address storageFallbackSigner = _storage.fallbackSigner;
        if (storageFallbackSigner != address(0)) {
            return storageFallbackSigner;
        }

        // If the signer in storage is zero, default to
        bytes memory appendedData = LibClone.argsOnERC1967(address(this), 0, 20);

        return address(uint160(bytes20(appendedData)));
    }
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import {ExecutionManifest} from "./IExecutionModule.sol";

type ModuleEntity is bytes24;
// ModuleEntity is a packed representation of a module function
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________0000000000000000 // unused

type ValidationConfig is bytes25;
// ValidationConfig is a packed representation of a validation function and flags for its configuration.
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________CC______________ // ValidationFlags
// 0x__________________________________________________00000000000000 // unused

type ValidationFlags is uint8;
// ValidationFlags layout:
// 0b00000___ // unused
// 0b_____A__ // isGlobal
// 0b______B_ // isSignatureValidation
// 0b_______C // isUserOpValidation

type HookConfig is bytes25;
// HookConfig is a packed representation of a hook function and flags for its configuration.
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________CC______________ // Hook Flags
//
// Hook flags layout:
// 0b00000___ // unused
// 0b_____A__ // hasPre (exec only)
// 0b______B_ // hasPost (exec only)
// 0b_______C // hook type (0 for exec, 1 for validation)

struct Call {
    // The target address for the account to call.
    address target;
    // The value to send with the call.
    uint256 value;
    // The calldata for the call.
    bytes data;
}

interface IModularAccount {
    event ExecutionInstalled(address indexed module, ExecutionManifest manifest);
    event ExecutionUninstalled(address indexed module, bool onUninstallSucceeded, ExecutionManifest manifest);
    event ValidationInstalled(address indexed module, uint32 indexed entityId);
    event ValidationUninstalled(address indexed module, uint32 indexed entityId, bool onUninstallSucceeded);

    /// @notice Standard execute method.
    /// @param target The target address for the account to call.
    /// @param value The value to send with the call.
    /// @param data The calldata for the call.
    /// @return The return data from the call.
    function execute(address target, uint256 value, bytes calldata data) external payable returns (bytes memory);

    /// @notice Standard executeBatch method.
    /// @dev If the target is a module, the call SHOULD revert. If any of the calls revert, the entire batch MUST
    /// revert.
    /// @param calls The array of calls.
    /// @return An array containing the return data from the calls.
    function executeBatch(Call[] calldata calls) external payable returns (bytes[] memory);

    /// @notice Execute a call using the specified runtime validation.
    /// @param data The calldata to send to the account.
    /// @param authorization The authorization data to use for the call. The first 24 bytes is a ModuleEntity which
    /// specifies which runtime validation to use, and the rest is sent as a parameter to runtime validation.
    function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization)
        external
        payable
        returns (bytes memory);

    /// @notice Install a module to the modular account.
    /// @param module The module to install.
    /// @param manifest the manifest describing functions to install.
    /// @param installData Optional data to be used by the account to handle the initial execution setup. Data
    /// encoding
    /// is implementation-specific.
    function installExecution(address module, ExecutionManifest calldata manifest, bytes calldata installData)
        external;

    /// @notice Uninstall a module from the modular account.
    /// @param module The module to uninstall.
    /// @param manifest the manifest describing functions to uninstall.
    /// @param uninstallData Optional data to be used by the account to handle the execution uninstallation. Data
    /// encoding is implementation-specific.
    function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData)
        external;

    /// @notice Installs a validation function across a set of execution selectors, and optionally mark it as a
    /// global validation function.
    /// @dev This does not validate anything against the manifest - the caller must ensure validity.
    /// @param validationConfig The validation function to install, along with configuration flags.
    /// @param selectors The selectors to install the validation function for.
    /// @param installData Optional data to be used by the account to handle the initial validation setup. Data
    /// encoding is implementation-specific.
    /// @param hooks Optional hooks to install and associate with the validation function. Data encoding is
    /// implementation-specific.
    function installValidation(
        ValidationConfig validationConfig,
        bytes4[] calldata selectors,
        bytes calldata installData,
        bytes[] calldata hooks
    ) external;

    /// @notice Uninstall a validation function from a set of execution selectors.
    /// @param validationFunction The validation function to uninstall.
    /// @param uninstallData Optional data to be used by the account to handle the validation uninstallation. Data
    /// encoding is implementation-specific.
    /// @param hookUninstallData Optional data to be used by the account to handle hook uninstallation. Data
    /// encoding
    /// is implementation-specific.
    function uninstallValidation(
        ModuleEntity validationFunction,
        bytes calldata uninstallData,
        bytes[] calldata hookUninstallData
    ) external;

    /// @notice Return a unique identifier for the account implementation.
    /// @dev This function MUST return a string in the format "vendor.account.semver". The vendor and account
    /// names MUST NOT contain a period character.
    /// @return The account ID.
    function accountId() external view returns (string memory);
}

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

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

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.5;

/**
 * Manage deposits and stakes.
 * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).
 * Stake is value locked for at least "unstakeDelay" by the staked entity.
 */
interface IStakeManager {
    event Deposited(address indexed account, uint256 totalDeposit);

    event Withdrawn(
        address indexed account,
        address withdrawAddress,
        uint256 amount
    );

    // Emitted when stake or unstake delay are modified.
    event StakeLocked(
        address indexed account,
        uint256 totalStaked,
        uint256 unstakeDelaySec
    );

    // Emitted once a stake is scheduled for withdrawal.
    event StakeUnlocked(address indexed account, uint256 withdrawTime);

    event StakeWithdrawn(
        address indexed account,
        address withdrawAddress,
        uint256 amount
    );

    /**
     * @param deposit         - The entity's deposit.
     * @param staked          - True if this entity is staked.
     * @param stake           - Actual amount of ether staked for this entity.
     * @param unstakeDelaySec - Minimum delay to withdraw the stake.
     * @param withdrawTime    - First block timestamp where 'withdrawStake' will be callable, or zero if already locked.
     * @dev Sizes were chosen so that deposit fits into one cell (used during handleOp)
     *      and the rest fit into a 2nd cell (used during stake/unstake)
     *      - 112 bit allows for 10^15 eth
     *      - 48 bit for full timestamp
     *      - 32 bit allows 150 years for unstake delay
     */
    struct DepositInfo {
        uint256 deposit;
        bool staked;
        uint112 stake;
        uint32 unstakeDelaySec;
        uint48 withdrawTime;
    }

    // API struct used by getStakeInfo and simulateValidation.
    struct StakeInfo {
        uint256 stake;
        uint256 unstakeDelaySec;
    }

    /**
     * Get deposit info.
     * @param account - The account to query.
     * @return info   - Full deposit information of given account.
     */
    function getDepositInfo(
        address account
    ) external view returns (DepositInfo memory info);

    /**
     * Get account balance.
     * @param account - The account to query.
     * @return        - The deposit (for gas payment) of the account.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * Add to the deposit of the given account.
     * @param account - The account to add to.
     */
    function depositTo(address account) external payable;

    /**
     * Add to the account's stake - amount and delay
     * any pending unstake is first cancelled.
     * @param _unstakeDelaySec - The new lock duration before the deposit can be withdrawn.
     */
    function addStake(uint32 _unstakeDelaySec) external payable;

    /**
     * Attempt to unlock the stake.
     * The value can be withdrawn (using withdrawStake) after the unstake delay.
     */
    function unlockStake() external;

    /**
     * Withdraw from the (unlocked) stake.
     * Must first call unlockStake and wait for the unstakeDelay to pass.
     * @param withdrawAddress - The address to send withdrawn value.
     */
    function withdrawStake(address payable withdrawAddress) external;

    /**
     * Withdraw from the deposit.
     * @param withdrawAddress - The address to send withdrawn value.
     * @param withdrawAmount  - The amount to withdraw.
     */
    function withdrawTo(
        address payable withdrawAddress,
        uint256 withdrawAmount
    ) external;
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

import "./PackedUserOperation.sol";

/**
 * Aggregated Signatures validator.
 */
interface IAggregator {
    /**
     * Validate aggregated signature.
     * Revert if the aggregated signature does not match the given list of operations.
     * @param userOps   - Array of UserOperations to validate the signature for.
     * @param signature - The aggregated signature.
     */
    function validateSignatures(
        PackedUserOperation[] calldata userOps,
        bytes calldata signature
    ) external view;

    /**
     * Validate signature of a single userOp.
     * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns
     * the aggregator this account uses.
     * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.
     * @param userOp        - The userOperation received from the user.
     * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps.
     *                        (usually empty, unless account and aggregator support some kind of "multisig".
     */
    function validateUserOpSignature(
        PackedUserOperation calldata userOp
    ) external view returns (bytes memory sigForUserOp);

    /**
     * Aggregate multiple signatures into a single value.
     * This method is called off-chain to calculate the signature to pass with handleOps()
     * bundler MAY use optimized custom code perform this aggregation.
     * @param userOps              - Array of UserOperations to collect the signatures from.
     * @return aggregatedSignature - The aggregated signature.
     */
    function aggregateSignatures(
        PackedUserOperation[] calldata userOps
    ) external view returns (bytes memory aggregatedSignature);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

interface INonceManager {

    /**
     * Return the next nonce for this sender.
     * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)
     * But UserOp with different keys can come with arbitrary order.
     *
     * @param sender the account address
     * @param key the high 192 bit of the nonce
     * @return nonce a full nonce to pass for next UserOp with this sender.
     */
    function getNonce(address sender, uint192 key)
    external view returns (uint256 nonce);

    /**
     * Manually increment the nonce of the sender.
     * This method is exposed just for completeness..
     * Account does NOT need to call it, neither during validation, nor elsewhere,
     * as the EntryPoint will update the nonce regardless.
     * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future
     * UserOperations will not pay extra for the first transaction with a given key.
     */
    function incrementNonce(uint192 key) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {
    ExecutionManifest,
    ManifestExecutionHook
} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol";
import {HookConfig, IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol";
import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol";

import {AccountStorage, ExecutionStorage, getAccountStorage, toSetValue} from "../account/AccountStorage.sol";
import {KnownSelectorsLib} from "../libraries/KnownSelectorsLib.sol";
import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol";
import {ModuleInstallCommonsLib} from "../libraries/ModuleInstallCommonsLib.sol";

/// @title Execution Install Delegate
/// @author Alchemy
/// @notice This contract acts as an external library which is meant to handle execution function installations and
/// uninstallations via delegatecall.
contract ExecutionInstallDelegate {
    using LinkedListSetLib for LinkedListSet;

    address internal immutable _THIS_ADDRESS;

    error ERC4337FunctionNotAllowed(bytes4 selector);
    error ExecutionFunctionAlreadySet(bytes4 selector);
    error ExecutionFunctionNotSet(bytes4 selector);
    error ExecutionHookNotSet(HookConfig hookConfig);
    error IModuleFunctionNotAllowed(bytes4 selector);
    error NullModule();
    error OnlyDelegateCall();

    modifier onlyDelegateCall() {
        if (address(this) == _THIS_ADDRESS) {
            revert OnlyDelegateCall();
        }
        _;
    }

    constructor() {
        _THIS_ADDRESS = address(this);
    }

    // External Functions

    /// @notice Update components according to the manifest.
    function installExecution(
        address module,
        ExecutionManifest calldata manifest,
        bytes calldata moduleInstallData
    ) external onlyDelegateCall {
        AccountStorage storage _storage = getAccountStorage();

        if (module == address(0)) {
            revert NullModule();
        }

        // Update components according to the manifest.
        uint256 length = manifest.executionFunctions.length;
        for (uint256 i = 0; i < length; ++i) {
            bytes4 selector = manifest.executionFunctions[i].executionSelector;
            bool skipRuntimeValidation = manifest.executionFunctions[i].skipRuntimeValidation;
            bool allowGlobalValidation = manifest.executionFunctions[i].allowGlobalValidation;
            _setExecutionFunction(selector, skipRuntimeValidation, allowGlobalValidation, module);
        }

        length = manifest.executionHooks.length;
        for (uint256 i = 0; i < length; ++i) {
            ManifestExecutionHook memory mh = manifest.executionHooks[i];
            LinkedListSet storage executionHooks = _storage.executionStorage[mh.executionSelector].executionHooks;
            HookConfig hookConfig = HookConfigLib.packExecHook({
                _module: module,
                _entityId: mh.entityId,
                _hasPre: mh.isPreHook,
                _hasPost: mh.isPostHook
            });
            ModuleInstallCommonsLib.addExecHooks(executionHooks, hookConfig);
        }

        length = manifest.interfaceIds.length;
        for (uint256 i = 0; i < length; ++i) {
            _storage.supportedIfaces[manifest.interfaceIds[i]] += 1;
        }

        ModuleInstallCommonsLib.onInstall(module, moduleInstallData, type(IModule).interfaceId);

        emit IModularAccount.ExecutionInstalled(module, manifest);
    }

    /// @notice Remove components according to the manifest, in reverse order (by component type) of their
    /// installation.
    function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData)
        external
        onlyDelegateCall
    {
        AccountStorage storage _storage = getAccountStorage();

        if (module == address(0)) {
            revert NullModule();
        }

        uint256 length = manifest.executionHooks.length;
        for (uint256 i = 0; i < length; ++i) {
            ManifestExecutionHook memory mh = manifest.executionHooks[i];
            LinkedListSet storage executionHooks = _storage.executionStorage[mh.executionSelector].executionHooks;
            HookConfig hookConfig = HookConfigLib.packExecHook({
                _module: module,
                _entityId: mh.entityId,
                _hasPre: mh.isPreHook,
                _hasPost: mh.isPostHook
            });
            _removeExecHooks(executionHooks, hookConfig);
        }

        length = manifest.executionFunctions.length;
        for (uint256 i = 0; i < length; ++i) {
            bytes4 selector = manifest.executionFunctions[i].executionSelector;
            _removeExecutionFunction(selector);
        }

        length = manifest.interfaceIds.length;
        for (uint256 i = 0; i < length; ++i) {
            _storage.supportedIfaces[manifest.interfaceIds[i]] -= 1;
        }

        // Clear the module storage for the account.
        bool onUninstallSuccess = ModuleInstallCommonsLib.onUninstall(module, uninstallData);

        emit IModularAccount.ExecutionUninstalled(module, onUninstallSuccess, manifest);
    }

    // Private Functions

    function _setExecutionFunction(
        bytes4 selector,
        bool skipRuntimeValidation,
        bool allowGlobalValidation,
        address module
    ) internal {
        ExecutionStorage storage _executionStorage = getAccountStorage().executionStorage[selector];

        if (_executionStorage.module != address(0)) {
            revert ExecutionFunctionAlreadySet(selector);
        }

        // Note that there is no check for native function selectors. Installing a function with a colliding
        // selector will lead to the installed function being unreachable.

        // Make sure incoming execution function is not a function in IModule
        if (KnownSelectorsLib.isIModuleFunction(uint32(selector))) {
            revert IModuleFunctionNotAllowed(selector);
        }

        // Also make sure it doesn't collide with functions defined by ERC-4337 and called by the entry point. This
        // prevents a malicious module from sneaking in a function with the same selector as e.g.
        // `validatePaymasterUserOp` and turning the account into their own personal paymaster.
        if (KnownSelectorsLib.isERC4337Function(uint32(selector))) {
            revert ERC4337FunctionNotAllowed(selector);
        }

        _executionStorage.module = module;
        _executionStorage.skipRuntimeValidation = skipRuntimeValidation;
        _executionStorage.allowGlobalValidation = allowGlobalValidation;
    }

    function _removeExecutionFunction(bytes4 selector) internal {
        ExecutionStorage storage _executionStorage = getAccountStorage().executionStorage[selector];

        if (_executionStorage.module == address(0)) {
            revert ExecutionFunctionNotSet(selector);
        }

        _executionStorage.module = address(0);
        _executionStorage.skipRuntimeValidation = false;
        _executionStorage.allowGlobalValidation = false;
    }

    function _removeExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal {
        if (!hooks.tryRemove(toSetValue(hookConfig))) {
            revert ExecutionHookNotSet(hookConfig);
        }
    }
}

File 20 of 70 : ModularAccountBase.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {getEmptyCalldataSlice} from "@erc6900/reference-implementation/helpers/EmptyCalldataSlice.sol";
import {ExecutionManifest} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol";
import {
    Call,
    HookConfig,
    IModularAccount,
    ModuleEntity,
    ValidationConfig,
    ValidationFlags
} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {HookConfig, HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol";
import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol";
import {SparseCalldataSegmentLib} from "@erc6900/reference-implementation/libraries/SparseCalldataSegmentLib.sol";
import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol";
import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {_coalescePreValidation, _coalesceValidation} from "../helpers/ValidationResHelpers.sol";
import {IModularAccountBase} from "../interfaces/IModularAccountBase.sol";
import {
    DensePostHookData,
    ExecutionLib,
    PHCallBuffer,
    RTCallBuffer,
    SigCallBuffer,
    UOCallBuffer
} from "../libraries/ExecutionLib.sol";
import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol";
import {MemManagementLib, MemSnapshot} from "../libraries/MemManagementLib.sol";
import {
    ValidationLocator, ValidationLocatorLib, ValidationLookupKey
} from "../libraries/ValidationLocatorLib.sol";
import {AccountBase} from "./AccountBase.sol";
import {AccountStorage, ValidationStorage, getAccountStorage, toSetValue} from "./AccountStorage.sol";
import {AccountStorageInitializable} from "./AccountStorageInitializable.sol";
import {ModularAccountView} from "./ModularAccountView.sol";
import {ModuleManagerInternals} from "./ModuleManagerInternals.sol";
import {TokenReceiver} from "./TokenReceiver.sol";

/// @title Modular Account Base
/// @author Alchemy
/// @notice This abstract contract is a modular account that is compliant with ERC-6900 standard. It supports
/// deferred actions during validation.
abstract contract ModularAccountBase is
    IModularAccount,
    IModularAccountBase,
    ModularAccountView,
    AccountStorageInitializable,
    AccountBase,
    IERC1271,
    IERC165,
    IAccountExecute,
    ModuleManagerInternals,
    UUPSUpgradeable,
    TokenReceiver
{
    using LinkedListSetLib for LinkedListSet;
    using ModuleEntityLib for ModuleEntity;
    using ValidationConfigLib for ValidationFlags;
    using HookConfigLib for HookConfig;
    using SparseCalldataSegmentLib for bytes;

    enum ValidationCheckingType {
        GLOBAL,
        SELECTOR,
        EITHER
    }

    // keccak256("EIP712Domain(uint256 chainId,address verifyingContract)")
    bytes32 internal constant _DOMAIN_SEPARATOR_TYPEHASH =
        0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;

    // keccak256("DeferredAction(uint256 nonce,uint48 deadline,bytes call)")
    bytes32 internal constant _DEFERRED_ACTION_TYPEHASH =
        0x9b23e06584efc6b65fc854cee55011d89f86485487b6db36aed7d23884711ea3;

    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 internal constant _INTERFACE_ID_INVALID = 0xffffffff;

    // bytes4(keccak256("isValidSignature(bytes32,bytes)"))
    bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e;
    bytes4 internal constant _1271_INVALID = 0xffffffff;

    address internal immutable _EXECUTION_INSTALL_DELEGATE;

    error CreateFailed();
    error DeferredActionSignatureInvalid();
    error RequireUserOperationContext();
    error SelfCallRecursionDepthExceeded();
    error SignatureValidationInvalid(ModuleEntity validationFunction);
    error UserOpValidationInvalid(ModuleEntity validationFunction);
    error UnexpectedAggregator(ModuleEntity validationFunction, address aggregator);
    error UnrecognizedFunction(bytes4 selector);
    error ValidationFunctionMissing(bytes4 selector);
    error DeferredValidationHasValidationHooks();

    // Wraps execution of a native function with runtime validation and hooks
    // Used for performCreate, execute, executeBatch, installExecution, uninstallExecution, installValidation,
    // uninstallValidation, upgradeToAndCall, updateFallbackSignerData.
    modifier wrapNativeFunction() {
        DensePostHookData postHookData = _checkPermittedCallerAndAssociatedHooks();

        _;

        ExecutionLib.doCachedPostHooks(postHookData);
    }

    constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
        AccountBase(entryPoint)
    {
        _disableInitializers();

        _EXECUTION_INSTALL_DELEGATE = address(executionInstallDelegate);
    }

    // EXTERNAL FUNCTIONS

    receive() external payable {}

    /// @notice Fallback function
    /// @dev Routes calls to execution functions based on the incoming msg.sig. If there's no module associated
    /// with this function selector, revert.
    ///
    /// @return The raw returned data from the invoked execution function.
    fallback(bytes calldata) external payable returns (bytes memory) {
        address execModule = getAccountStorage().executionStorage[msg.sig].module;
        if (execModule == address(0)) {
            revert UnrecognizedFunction(msg.sig);
        }
        DensePostHookData postHookData = _checkPermittedCallerAndAssociatedHooks();

        // execute the function, bubbling up any reverts
        ExecutionLib.callBubbleOnRevertTransient(execModule, 0 wei, msg.data);
        bytes memory execReturnData = ExecutionLib.collectReturnData();

        ExecutionLib.doCachedPostHooks(postHookData);

        return execReturnData;
    }

    /// @inheritdoc IModularAccountBase
    function performCreate(uint256 value, bytes calldata initCode, bool isCreate2, bytes32 salt)
        external
        payable
        virtual
        override
        wrapNativeFunction
        returns (address createdAddr)
    {
        assembly ("memory-safe") {
            // Load the free memory pointer.
            let fmp := mload(0x40)

            // Get the initCode length.
            let len := initCode.length

            // Copy the initCode from callata to memory at the free memory pointer.
            calldatacopy(fmp, initCode.offset, len)

            switch isCreate2
            case 1 { createdAddr := create2(value, fmp, len, salt) }
            default { createdAddr := create(value, fmp, len) }

            if iszero(createdAddr) {
                // If creation failed (the address returned is zero), revert with CreateFailed().
                mstore(0x00, 0x7e16b8cd)
                revert(0x1c, 0x04)
            }
        }
    }

    /// @inheritdoc IAccountExecute
    /// @notice Execution function that allows UO context to be passed to execution hooks
    /// @dev This function is only callable by the EntryPoint
    function executeUserOp(PackedUserOperation calldata userOp, bytes32) external override {
        _requireFromEntryPoint();

        ValidationLocator locator = ValidationLocatorLib.loadFromNonce(userOp.nonce);

        HookConfig[] memory validationAssocExecHooks =
            MemManagementLib.loadExecHooks(getAccountStorage().validationStorage[locator.lookupKey()]);

        PHCallBuffer callBuffer;
        if (validationAssocExecHooks.length > 0) {
            callBuffer = ExecutionLib.allocatePreExecHookCallBuffer(msg.data);
        }

        DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, callBuffer);

        bytes memory callData = ExecutionLib.getExecuteUOCallData(callBuffer, userOp.callData);

        // Manually call self, without collecting return data unless there's a revert.
        ExecutionLib.callBubbleOnRevert(address(this), 0, callData);

        ExecutionLib.doCachedPostHooks(postHookData);
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation.
    function execute(address target, uint256 value, bytes calldata data)
        external
        payable
        override
        wrapNativeFunction
        returns (bytes memory result)
    {
        ExecutionLib.callBubbleOnRevertTransient(target, value, data);

        // Only return data if not called by the EntryPoint
        if (msg.sender != address(_ENTRY_POINT)) {
            result = ExecutionLib.collectReturnData();
        }
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation function.
    function executeBatch(Call[] calldata calls)
        external
        payable
        override
        wrapNativeFunction
        returns (bytes[] memory results)
    {
        uint256 callsLength = calls.length;

        if (msg.sender != address(_ENTRY_POINT)) {
            results = new bytes[](callsLength);

            for (uint256 i = 0; i < callsLength; ++i) {
                ExecutionLib.callBubbleOnRevertTransient(calls[i].target, calls[i].value, calls[i].data);

                results[i] = ExecutionLib.collectReturnData();
            }
        } else {
            for (uint256 i = 0; i < callsLength; ++i) {
                ExecutionLib.callBubbleOnRevertTransient(calls[i].target, calls[i].value, calls[i].data);
            }
        }
    }

    /// @inheritdoc IModularAccount
    function executeWithRuntimeValidation(bytes calldata data, bytes calldata authorization)
        external
        payable
        returns (bytes memory)
    {
        (ValidationLocator locator, bytes calldata authorizationData) =
            ValidationLocatorLib.loadFromSignature(authorization);

        ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[locator.lookupKey()];

        // Check if the runtime validation function is allowed to be called
        _checkIfValidationAppliesCallData(
            data,
            locator.lookupKey(),
            // Unfortunately, have to avoid declaring a `bool isGlobalValidation` to avoid stack too deep issues.
            locator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR
        );

        RTCallBuffer rtCallBuffer = _doRuntimeValidation(locator.lookupKey(), data, authorizationData);

        // If runtime validation passes, run exec hooks associated with the validator
        HookConfig[] memory validationAssocExecHooks = MemManagementLib.loadExecHooks(_validationStorage);

        PHCallBuffer phCallBuffer;
        if (validationAssocExecHooks.length > 0) {
            phCallBuffer = ExecutionLib.convertToPreHookCallBuffer(rtCallBuffer, data);
        }
        DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, phCallBuffer);

        // Execute the call, reusing the already-allocated RT call buffers, if it exists.
        // In practice, this is cheaper than attempting to coalesce the (possibly two) buffers.
        ExecutionLib.executeRuntimeSelfCall(rtCallBuffer, data);
        bytes memory returnData = ExecutionLib.collectReturnData();

        ExecutionLib.doCachedPostHooks(postHookData);

        return returnData;
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation.
    function installExecution(
        address module,
        ExecutionManifest calldata manifest,
        bytes calldata moduleInstallData
    ) external override wrapNativeFunction {
        // Access params to prevent compiler unused parameter flags.
        (module, manifest, moduleInstallData);
        address delegate = _EXECUTION_INSTALL_DELEGATE;
        ExecutionLib.delegatecallBubbleOnRevertTransient(delegate);
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation.
    function uninstallExecution(
        address module,
        ExecutionManifest calldata manifest,
        bytes calldata moduleUninstallData
    ) external override wrapNativeFunction {
        // Access params to prevent compiler unused parameter flags.
        (module, manifest, moduleUninstallData);
        address delegate = _EXECUTION_INSTALL_DELEGATE;
        ExecutionLib.delegatecallBubbleOnRevertTransient(delegate);
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation.
    /// @dev This function can be used to update (to a certain degree) previously installed validation functions.
    ///      - preValidationHook, executionHooks, and selectors can be added later. Though they won't be deleted.
    ///      - isGlobal and isSignatureValidation can also be updated later.
    function installValidation(
        ValidationConfig validationConfig,
        bytes4[] calldata selectors,
        bytes calldata installData,
        bytes[] calldata hooks
    ) external virtual wrapNativeFunction {
        _installValidation(validationConfig, selectors, installData, hooks);
    }

    /// @inheritdoc IModularAccount
    /// @notice May be validated by a global validation.
    function uninstallValidation(
        ModuleEntity validationFunction,
        bytes calldata uninstallData,
        bytes[] calldata hookUninstallData
    ) external wrapNativeFunction {
        _uninstallValidation(validationFunction, uninstallData, hookUninstallData);
    }

    /// @inheritdoc IERC1271
    function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4) {
        (ValidationLocator locator, bytes calldata signatureRemainder) =
            ValidationLocatorLib.loadFromSignature(signature);

        return _isValidSignature(locator.lookupKey(), hash, signatureRemainder);
    }

    /// @inheritdoc IERC165
    /// @notice ERC-165 introspection
    /// @dev returns true for `IERC165.interfaceId` and false for `0xFFFFFFFF`
    /// @param interfaceId interface id to check against
    /// @return bool support for specific interface
    function supportsInterface(bytes4 interfaceId) external view override returns (bool) {
        if (interfaceId == _INTERFACE_ID_INVALID) {
            return false;
        }
        if (
            interfaceId == type(IERC721Receiver).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId
                || interfaceId == type(IERC165).interfaceId
        ) {
            return true;
        }

        return getAccountStorage().supportedIfaces[interfaceId] > 0;
    }

    /// @inheritdoc IModularAccount
    function accountId() external pure virtual returns (string memory);

    /// @inheritdoc UUPSUpgradeable
    /// @notice May be validated by a global validation.
    function upgradeToAndCall(address newImplementation, bytes calldata data)
        public
        payable
        virtual
        override
        onlyProxy
        wrapNativeFunction
    {
        super.upgradeToAndCall(newImplementation, data);
    }

    // INTERNAL FUNCTIONS

    // Parent function validateUserOp enforces that this call can only be made by the EntryPoint
    function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
        internal
        override
        returns (uint256 validationData)
    {
        ValidationLocator locator = ValidationLocatorLib.loadFromNonce(userOp.nonce);

        bytes calldata userOpSignature = userOp.signature;

        /// The calldata layout is unique for deferred validation installation.
        /// Byte indices are [inclusive, exclusive] and relative to the start of the signature after the locator is
        /// decoded and removed.
        ///      [0:4] : uint32, encodedDatalength.
        ///      [4:(4 + encodedDatalength)] : bytes, abi-encoded deferred action data.
        ///      [(4 + encodedDataLength):(8 + encodedDataLength)] : uint32, deferredActionSigLength.
        ///      [(8 + encodedDataLength):(8 + deferredActionSigLength + encodedDataLength)] : bytes,
        ///         deferred action sig. This is the signature passed to the outer validation decoded earlier.
        ///      [(8 + deferredActionSigLength + encodedDataLength):] : bytes, userOpSignature. This is the
        ///         signature passed to the inner validation.
        if (locator.hasDeferredAction()) {
            // Use inner validation as a 1271 validation for the deferred action, then use the outer
            // validation to validate the UO.

            // Get the length of the deferred action data.
            uint256 encodedDataLength = uint32(bytes4(userOpSignature[:4]));

            // Load the pointer to the encoded data.
            bytes calldata encodedData = userOpSignature[4:4 + encodedDataLength];

            // Get the deferred action signature length.
            uint256 deferredActionSigLength =
                uint32(bytes4(userOpSignature[4 + encodedDataLength:8 + encodedDataLength]));

            // Get the deferred installation signature, which is passed to the outer validation to handle the
            // deferred action.
            bytes calldata deferredActionSig =
                userOpSignature[8 + encodedDataLength:8 + encodedDataLength + deferredActionSigLength];

            //Validate the signature.

            // Freeze the free-memory pointer, since we won't need to use anything from the deferred action
            // validation memory.
            MemSnapshot memSnapshot = MemManagementLib.freezeFMP();

            uint48 deadline = _handleDeferredAction(userOp.nonce, encodedData, deferredActionSig);

            // Restore the free memory pointer.
            MemManagementLib.restoreFMP(memSnapshot);

            // Update the validation data with the deadline.
            validationData = uint256(deadline) << 160;

            // Update the UserOp signature to the remaining bytes.
            userOpSignature = userOpSignature[8 + encodedDataLength + deferredActionSigLength:];
        }

        _checkIfValidationAppliesCallData(
            userOp.callData,
            locator.lookupKey(),
            locator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR
        );

        // Check if there are execution hooks associated with the validator, and revert if the call isn't to
        // `executeUserOp`. This check must be here because if context isn't passed, we can't tell in execution
        // which hooks should have ran.
        if (
            getAccountStorage().validationStorage[locator.lookupKey()].executionHookCount > 0
                && bytes4(userOp.callData[:4]) != this.executeUserOp.selector
        ) {
            revert RequireUserOperationContext();
        }
        uint256 userOpValidationRes = _doUserOpValidation(userOp, userOpHash, locator.lookupKey(), userOpSignature);

        // We only coalesce validations if the validation data from deferred installation is nonzero.
        if (validationData != 0) {
            validationData = _coalesceValidation(validationData, userOpValidationRes);
        } else {
            validationData = userOpValidationRes;
        }
    }

    /// @return The deadline of the deferred action
    function _handleDeferredAction(uint256 userOpNonce, bytes calldata encodedData, bytes calldata sig)
        internal
        returns (uint48)
    {
        // The inner validation, deadline, and deferred call bytes are all at fixed positions in the encoded data.
        // [:21] = ValidationLocator defActionValidationLocator
        // [21:27] = uint48 deadline
        // [27:] = bytes deferredCall

        ValidationLocator defActionValidationLocator = ValidationLocator.wrap(uint168(bytes21(encodedData[:21])));

        ValidationStorage storage _validationStorage =
            getAccountStorage().validationStorage[defActionValidationLocator.lookupKey()];

        // Because this bypasses UO validation hooks, we require that the validation used does not include any
        // validation hooks.
        if (_validationStorage.validationHookCount != 0) {
            revert DeferredValidationHasValidationHooks();
        }

        uint48 deadline = uint48(bytes6(encodedData[21:27]));

        bytes32 typedDataHash = _computeDeferredActionHash(userOpNonce, deadline, encodedData[27:]);

        // Check if the outer validation applies to the function call
        _checkIfValidationAppliesCallData(
            encodedData[27:],
            defActionValidationLocator.lookupKey(),
            defActionValidationLocator.isGlobal() ? ValidationCheckingType.GLOBAL : ValidationCheckingType.SELECTOR
        );

        // Handle the signature validation
        _validateDeferredActionSignature(typedDataHash, sig, defActionValidationLocator.lookupKey());

        // Run the validation associated execution hooks, allocating a call buffer as needed.
        HookConfig[] memory validationAssocExecHooks = MemManagementLib.loadExecHooks(_validationStorage);

        PHCallBuffer callBuffer;
        if (validationAssocExecHooks.length > 0) {
            callBuffer = ExecutionLib.allocatePreExecHookCallBuffer(encodedData[27:]);
        }

        DensePostHookData postHookData = ExecutionLib.doPreHooks(validationAssocExecHooks, callBuffer);

        // Perform the deferred action's self call on the account.
        ExecutionLib.callBubbleOnRevertTransient(address(this), 0, encodedData[27:]);

        // Do the cached post hooks
        ExecutionLib.doCachedPostHooks(postHookData);

        return deadline;
    }

    // To support gas estimation, we don't fail early when the failure is caused by a signature failure
    function _doUserOpValidation(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        ValidationLookupKey validationLookupKey,
        bytes calldata signature
    ) internal returns (uint256) {
        ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey];

        // Do preUserOpValidation hooks
        HookConfig[] memory preUserOpValidationHooks = MemManagementLib.loadValidationHooks(_validationStorage);

        uint256 validationRes;
        UOCallBuffer userOpCallBuffer;
        if (!_validationIsNative(validationLookupKey) || preUserOpValidationHooks.length > 0) {
            userOpCallBuffer = ExecutionLib.allocateUserOpValidationCallBuffer(userOp, userOpHash);
        }
        bytes calldata currentSignatureSlice;
        for (uint256 i = preUserOpValidationHooks.length; i > 0; i) {
            // Decrement here, instead of in the loop body, to convert from length to an index.
            unchecked {
                --i;
            }

            (currentSignatureSlice, signature) =
                signature.advanceSegmentIfAtIndex(uint8(preUserOpValidationHooks.length - i - 1));

            ModuleEntity uoValidationHook = preUserOpValidationHooks[i].moduleEntity();

            uint256 currentValidationRes =
                ExecutionLib.invokeUserOpCallBuffer(userOpCallBuffer, uoValidationHook, currentSignatureSlice);

            if (uint160(currentValidationRes) > 1) {
                // If the aggregator is not 0 or 1, it is an unexpected value
                revert UnexpectedAggregator(uoValidationHook, address(uint160(currentValidationRes)));
            }
            validationRes = _coalescePreValidation(validationRes, currentValidationRes);
        }

        // Run the user op validation function
        {
            currentSignatureSlice = signature.getFinalSegment();

            uint256 currentValidationRes =
                _execUserOpValidation(validationLookupKey, userOpHash, currentSignatureSlice, userOpCallBuffer);

            if (preUserOpValidationHooks.length != 0) {
                // If we have other validation data we need to coalesce with
                validationRes = _coalesceValidation(validationRes, currentValidationRes);
            } else {
                validationRes = currentValidationRes;
            }
        }

        return validationRes;
    }

    function _doRuntimeValidation(
        ValidationLookupKey validationLookupKey,
        bytes calldata callData,
        bytes calldata authorizationData
    ) internal returns (RTCallBuffer) {
        ValidationStorage storage _validationData = getAccountStorage().validationStorage[validationLookupKey];

        // run all preRuntimeValidation hooks
        HookConfig[] memory preRuntimeValidationHooks = MemManagementLib.loadValidationHooks(_validationData);

        RTCallBuffer callBuffer;
        if (!_validationIsNative(validationLookupKey) || preRuntimeValidationHooks.length > 0) {
            callBuffer = ExecutionLib.allocateRuntimeValidationCallBuffer(callData, authorizationData);
        }

        for (uint256 i = preRuntimeValidationHooks.length; i > 0;) {
            // Decrement here, instead of in the loop update step, to handle the case where the length is 0.
            unchecked {
                --i;
            }

            bytes calldata currentAuthSegment;

            (currentAuthSegment, authorizationData) =
                authorizationData.advanceSegmentIfAtIndex(uint8(preRuntimeValidationHooks.length - i - 1));

            ExecutionLib.invokeRuntimeCallBufferPreValidationHook(
                callBuffer, preRuntimeValidationHooks[i], currentAuthSegment
            );
        }

        authorizationData = authorizationData.getFinalSegment();

        _execRuntimeValidation(validationLookupKey, callBuffer, authorizationData);

        return callBuffer;
    }

    // solhint-disable-next-line no-empty-blocks
    function _authorizeUpgrade(address newImplementation) internal override {}

    /**
     * Order of operations:
     *      1. Check if the sender is the entry point, the account itself, or the selector called is public.
     *          - Yes: Return an empty array, there are no post executionHooks.
     *          - No: Continue
     *      2. Check if the called selector (msg.sig) is included in the set of selectors the msg.sender can
     *         directly call.
     *          - Yes: Continue
     *          - No: Revert, the caller is not allowed to call this selector
     *      3. If there are runtime validation hooks associated with this caller-sig combination, run them.
     *      4. Run the pre executionHooks associated with this caller-sig combination, and return the
     *         post executionHooks to run later.
     */
    function _checkPermittedCallerAndAssociatedHooks() internal returns (DensePostHookData) {
        AccountStorage storage _storage = getAccountStorage();
        HookConfig[] memory execHooks;

        RTCallBuffer rtCallBuffer;

        // We only need to handle execution hooks when the sender is not the entry point or the account itself,
        // and the selector isn't public.
        if (
            msg.sender != address(_ENTRY_POINT) && msg.sender != address(this)
                && !_storage.executionStorage[msg.sig].skipRuntimeValidation
        ) {
            ValidationLookupKey directCallValidationKey = ValidationLocatorLib.directCallLookupKey(msg.sender);

            _checkIfValidationAppliesCallData(msg.data, directCallValidationKey, ValidationCheckingType.EITHER);

            // Direct call is allowed, run associated execution & validation hooks

            // Validation hooks
            HookConfig[] memory preRuntimeValidationHooks =
                MemManagementLib.loadValidationHooks(_storage.validationStorage[directCallValidationKey]);

            uint256 preRuntimeValidationHooksLength = preRuntimeValidationHooks.length;
            if (preRuntimeValidationHooksLength > 0) {
                rtCallBuffer = ExecutionLib.allocateRuntimeValidationCallBuffer(msg.data, getEmptyCalldataSlice());
            }

            for (uint256 i = preRuntimeValidationHooksLength; i > 0;) {
                // Decrement here, instead of in the loop body, to convert from length to an index.
                unchecked {
                    --i;
                }

                ExecutionLib.invokeRuntimeCallBufferPreValidationHook(
                    rtCallBuffer, preRuntimeValidationHooks[i], getEmptyCalldataSlice()
                );
            }

            //Load all execution hooks: both associated with the selector and the validation function.
            execHooks = MemManagementLib.loadExecHooks(
                _storage.executionStorage[msg.sig], _storage.validationStorage[directCallValidationKey]
            );
        } else {
            // If the sender is the entry point or the account itself, or the selector is public, this indicates
            // that validation was done elsewhere. We only need to run selector-associated execution hooks.
            execHooks = MemManagementLib.loadExecHooks(_storage.executionStorage[msg.sig]);
        }

        PHCallBuffer preHookCallBuffer;
        if (execHooks.length > 0) {
            preHookCallBuffer = ExecutionLib.convertToPreHookCallBuffer(rtCallBuffer, msg.data);
        }

        // Exec hooks associated with the selector
        DensePostHookData postHookData = ExecutionLib.doPreHooks(execHooks, preHookCallBuffer);

        return postHookData;
    }

    function _execUserOpValidation(
        ValidationLookupKey validationLookupKey,
        bytes32 hash,
        bytes calldata signatureSegment,
        UOCallBuffer callBuffer
    ) internal virtual returns (uint256) {
        (hash); // unused in ModularAccountBase, but used in SemiModularAccountBase
        ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey];

        ModuleEntity userOpValidationFunction = validationLookupKey.moduleEntity(_validationStorage);

        if (!_validationStorage.validationFlags.isUserOpValidation()) {
            revert UserOpValidationInvalid(userOpValidationFunction);
        }

        ExecutionLib.convertToValidationBuffer(callBuffer);

        return ExecutionLib.invokeUserOpCallBuffer(callBuffer, userOpValidationFunction, signatureSegment);
    }

    function _execRuntimeValidation(
        ValidationLookupKey validationLookupKey,
        RTCallBuffer callBuffer,
        bytes calldata authorization
    ) internal virtual {
        ValidationStorage storage _validationData = getAccountStorage().validationStorage[validationLookupKey];
        ModuleEntity runtimeValidationFunction = validationLookupKey.moduleEntity(_validationData);
        ExecutionLib.invokeRuntimeCallBufferValidation(callBuffer, runtimeValidationFunction, authorization);
    }

    function _computeDeferredActionHash(uint256 userOpNonce, uint48 deadline, bytes calldata selfCall)
        internal
        view
        returns (bytes32)
    {
        // Note:
        // - A zero deadline translates to "no deadline"
        // - The user op nonce also includes the data for:
        //   - Which validation function to use
        //   - Whether or not a deferred action is included
        //   - Whether or not the validation is used as a global validation.

        // Compute the hash without permanently allocating memory for each step.
        // The following is equivalent to:
        // keccak256(
        //     abi.encode(
        //         _DEFERRED_ACTION_TYPEHASH,
        //         nonce,
        //         deadline,
        //         keccak256(selfCall)
        //     )
        // )

        // Compute the struct hash, then convert it to a typed data hash.
        bytes32 structHash;

        assembly ("memory-safe") {
            // Get the hash of the dynamic-length encoded install call
            let fmp := mload(0x40)
            calldatacopy(fmp, selfCall.offset, selfCall.length)
            let selfCallHash := keccak256(fmp, selfCall.length)

            // Compute the struct hash
            let ptr := fmp
            mstore(ptr, _DEFERRED_ACTION_TYPEHASH)
            ptr := add(ptr, 0x20)
            mstore(ptr, userOpNonce)
            ptr := add(ptr, 0x20)
            // Clear the upper bits of the deadline, in case the caller didn't.
            mstore(ptr, and(deadline, 0xffffffffffff))
            ptr := add(ptr, 0x20)
            mstore(ptr, selfCallHash)

            // Compute the struct hash
            structHash := keccak256(fmp, 0x80)
        }

        bytes32 typedDataHash = MessageHashUtils.toTypedDataHash(_domainSeparator(), structHash);

        return typedDataHash;
    }

    function _validateDeferredActionSignature(
        bytes32 defActionTypedDataHash,
        bytes calldata signature,
        ValidationLookupKey deferredSigValidationLookupKey
    ) internal view {
        // Validate the 1271 signature.
        SigCallBuffer sigCallBuffer;
        if (!_validationIsNative(deferredSigValidationLookupKey)) {
            sigCallBuffer = ExecutionLib.allocateSigCallBuffer(defActionTypedDataHash, signature);
        }

        if (
            _exec1271Validation(sigCallBuffer, defActionTypedDataHash, deferredSigValidationLookupKey, signature)
                != _1271_MAGIC_VALUE
        ) {
            revert DeferredActionSignatureInvalid();
        }
    }

    function _isValidSignature(ValidationLookupKey validationLookupKey, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bytes4)
    {
        ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey];

        HookConfig[] memory preSignatureValidationHooks = MemManagementLib.loadValidationHooks(_validationStorage);

        SigCallBuffer sigCallBuffer;
        if (!_validationIsNative(validationLookupKey) || preSignatureValidationHooks.length > 0) {
            sigCallBuffer = ExecutionLib.allocateSigCallBuffer(hash, signature);
        }
        for (uint256 i = preSignatureValidationHooks.length; i > 0;) {
            // Decrement here, instead of in the loop body, to convert from length to an index.
            unchecked {
                --i;
            }

            bytes calldata currentSignatureSegment;

            (currentSignatureSegment, signature) =
                signature.advanceSegmentIfAtIndex(uint8(preSignatureValidationHooks.length - i - 1));

            ExecutionLib.invokePreSignatureValidationHook(
                sigCallBuffer, preSignatureValidationHooks[i], currentSignatureSegment
            );
        }
        signature = signature.getFinalSegment();

        return _exec1271Validation(sigCallBuffer, hash, validationLookupKey, signature);
    }

    function _exec1271Validation(
        SigCallBuffer buffer,
        bytes32 hash,
        ValidationLookupKey validationLookupKey,
        bytes calldata signatureSegment
    ) internal view virtual returns (bytes4) {
        (hash); // unused in ModularAccountBase, but used in SemiModularAccountBase
        ValidationStorage storage _validationStorage = getAccountStorage().validationStorage[validationLookupKey];

        ModuleEntity sigValidation = validationLookupKey.moduleEntity(_validationStorage);

        if (!_validationStorage.validationFlags.isSignatureValidation()) {
            revert SignatureValidationInvalid(sigValidation);
        }

        if (ExecutionLib.invokeSignatureValidation(buffer, sigValidation, signatureSegment) == _1271_MAGIC_VALUE) {
            return _1271_MAGIC_VALUE;
        }
        return _1271_INVALID;
    }

    function _isValidationGlobal(ValidationLookupKey validationFunction) internal view virtual returns (bool) {
        return getAccountStorage().validationStorage[validationFunction].validationFlags.isGlobal();
    }

    function _checkIfValidationAppliesCallData(
        bytes calldata callData,
        ValidationLookupKey validationFunction,
        ValidationCheckingType checkingType
    ) internal view {
        if (callData.length < 4) {
            revert UnrecognizedFunction(bytes4(callData));
        }

        bytes4 outerSelector = bytes4(callData);
        if (outerSelector == this.executeUserOp.selector) {
            // If the selector is executeUserOp, pull the actual selector from the following data,
            // and trim the calldata to ensure the self-call decoding is still accurate.
            callData = callData[4:];
            outerSelector = bytes4(callData[:4]);
        }

        _checkIfValidationAppliesSelector(outerSelector, validationFunction, checkingType);

        if (outerSelector == IModularAccount.execute.selector) {
            address target = MemManagementLib.getExecuteTarget(callData);

            if (target == address(this)) {
                // There is no point to call `execute` to recurse exactly once - this is equivalent to just having
                // the calldata as a top-level call.
                revert SelfCallRecursionDepthExceeded();
            }
        } else if (outerSelector == IModularAccount.executeBatch.selector) {
            // executeBatch may be used to batch account actions together, by targetting the account itself.
            // If this is done, we must ensure all of the inner calls are allowed by the provided validation
            // function.
            _checkExecuteBatchValidationApplicability(callData[4:], validationFunction, checkingType);
        }
    }

    /// @notice Checks if the validation function is allowed to perform this call to `executeBatch`.
    /// @param callData The calldata to check, excluding the `executeBatch` selector.
    /// @param validationFunction The validation function to check against.
    /// @param checkingType The type of validation checking to perform.
    function _checkExecuteBatchValidationApplicability(
        bytes calldata callData,
        ValidationLookupKey validationFunction,
        ValidationCheckingType checkingType
    ) internal view {
        // Equivalent to the following code, but without using memory.

        // (Call[] memory calls) = abi.decode(callData, (Call[]));

        // for (uint256 i = 0; i < calls.length; ++i) {
        //     if (calls[i].target == address(this)) {
        //         bytes4 nestedSelector = bytes4(calls[i].data[:4]);

        //         if (
        //             nestedSelector == IModularAccount.execute.selector
        //                 || nestedSelector == IModularAccount.executeBatch.selector
        //         ) {
        //
        //             revert SelfCallRecursionDepthExceeded();
        //         }

        //         _checkIfValidationAppliesSelector(nestedSelector, validationFunction, checkingType);
        //     }
        // }

        // The following is adapted from the compiler-generated ABI decoder for the `Call[] calldata` parameter
        // type. See test/mocks/MockDecoder.sol for more info.
        // This allows the decoding behavior here, in the validation step, to match what would happen during the
        // actual execution of `executeBatch`.
        // This follows the compiler-generated behavior of:
        // - asserting the data to load fits in the remaining space of the current `bytes calldata`.
        // - asserting that the ABI-encoded offsets and lengths do not exceed the constant value
        // 0xffffffffffffffff.

        // The end of allowed calldata to read. Declared in an outer context to make available to multiple code
        // blocks.
        uint256 dataEnd;

        // The absolute offset of the start of the `Call[]` array.
        uint256 arrayPos;
        // The length of the `Call[]` array.
        uint256 callsLength;

        // This block is retrieving the actual Call[] location and length, asserting it doesn't go out of bounds.
        assembly ("memory-safe") {
            // Set up the "safe data decoding range"
            let headStart := callData.offset
            dataEnd := add(headStart, callData.length)

            // Assert it is safe to load the offset
            if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }

            // Load and sanitize the offset
            let relOffset := calldataload(callData.offset)
            if gt(relOffset, 0xffffffffffffffff) { revert(0, 0) }

            // Convert from a relative offset to an absolute offset.
            let absOffset := add(headStart, relOffset)

            // Assert it is safe to load the length
            if iszero(slt(add(absOffset, 0x1f), dataEnd)) { revert(0, 0) }

            // Load and sanitize the length
            callsLength := calldataload(absOffset)
            if gt(callsLength, 0xffffffffffffffff) { revert(0, 0) }

            // Load the array position, and check that it fits within the alloted length.
            arrayPos := add(absOffset, 0x20)
            if gt(add(arrayPos, mul(callsLength, 0x20)), dataEnd) { revert(0, 0) }
        }

        // Now, we have the array length and data bounds.
        // Iterate through the array elements, checking:
        // - If the target is this account, assert that:
        //   - the selector in the data field is not `execute` or `executeBatch`.
        //   - the provided validation is allowed to call the selector.

        for (uint256 i = 0; i < callsLength; ++i) {
            address callTarget;
            uint256 structAbsOffset;

            // This block is retrieving the actual calls[i] struct location and contents, asserting it doesn't go
            // out of bounds.
            assembly ("memory-safe") {
                // Load and sanitize the struct offset.
                // This is still safe to load, from the bounds check above.
                let structRelOffset := calldataload(add(arrayPos, mul(i, 0x20)))
                if gt(structRelOffset, 0xffffffffffffffff) { revert(0, 0) }
                // Validate struct offset. If the offset points to a location with < 3 words of space before the
                // end of data, revert.
                if iszero(slt(structRelOffset, sub(sub(dataEnd, arrayPos), sub(0x60, 1)))) { revert(0, 0) }

                structAbsOffset := add(arrayPos, structRelOffset)

                // Load the address from the struct, and sanitize its contents, to mirror the behavior of the ABI
                // decoder.
                callTarget := calldataload(structAbsOffset)
                if iszero(eq(and(callTarget, 0xffffffffffffffffffffffffffffffffffffffff), callTarget)) {
                    revert(0, 0)
                }
            }

            if (callTarget == address(this)) {
                // In this case, we must load the selector, deny if it's `execute` or `executeBatch`, and check
                // validation applicability.

                uint32 selector;

                // This block is retrieving the selector from the first 4 bytes of calls[i].data, asserting it
                // doesn't go out of bounds and that the data is at least 4 bytes long.
                assembly ("memory-safe") {
                    // Load and sanitize the data offset.
                    let dataRelOffset := calldataload(add(structAbsOffset, 0x40))
                    if gt(dataRelOffset, 0xffffffffffffffff) { revert(0, 0) }

                    // Validate data offset. If the offset points to a location with < 1 words of space before the
                    // end of data, revert.
                    if iszero(slt(dataRelOffset, sub(sub(dataEnd, structAbsOffset), sub(0x20, 1)))) {
                        revert(0, 0)
                    }

                    let dataAbsOffset := add(structAbsOffset, dataRelOffset)

                    // Load and sanitize the data length.
                    let dataLength := calldataload(dataAbsOffset)
                    if gt(dataLength, 0xffffffff) { revert(0, 0) }

                    // Get the data offset, and assert that the following data fits into the bounded calldata
                    // range.
                    let dataOffset := add(dataAbsOffset, 0x20)
                    if sgt(dataOffset, sub(dataEnd, mul(dataLength, 0x01))) { revert(0, 0) }

                    // Finally, load the selector being called. This will be the first 4 bytes of the data.
                    // If the data length is less than 4, revert.
                    if slt(dataLength, 4) { revert(0, 0) }
                    selector := shr(224, calldataload(dataOffset))
                }

                if (selector == uint32(this.execute.selector) || selector == uint32(this.executeBatch.selector)) {
                    // To prevent arbitrarily-deep recursive checking, we limit the depth of self-calls to one
                    // for the purposes of batching.
                    // This means that all self-calls must occur at the top level of the batch.
                    // Note that modules of other contracts using `executeWithRuntimeValidation` may still
                    // independently call into this account with a different validation function, allowing
                    // composition of multiple batches.

                    revert SelfCallRecursionDepthExceeded();
                }

                _checkIfValidationAppliesSelector(bytes4(selector), validationFunction, checkingType);
            }
        }
    }

    function _checkIfValidationAppliesSelector(
        bytes4 selector,
        ValidationLookupKey validationFunction,
        ValidationCheckingType checkingType
    ) internal view {
        // Check that the provided validation function is applicable to the selector

        if (checkingType == ValidationCheckingType.GLOBAL) {
            if (!_globalValidationApplies(selector, validationFunction)) {
                revert ValidationFunctionMissing(selector);
            }
        } else if (checkingType == ValidationCheckingType.SELECTOR) {
            if (!_selectorValidationApplies(selector, validationFunction)) {
                revert ValidationFunctionMissing(selector);
            }
        } else {
            if (
                !_globalValidationApplies(selector, validationFunction)
                    && !_selectorValidationApplies(selector, validationFunction)
            ) {
                revert ValidationFunctionMissing(selector);
            }
        }
    }

    function _globalValidationApplies(bytes4 selector, ValidationLookupKey validationFunction)
        internal
        view
        returns (bool)
    {
        return _globalValidationAllowed(selector) && _isValidationGlobal(validationFunction);
    }

    function _globalValidationAllowed(bytes4 selector) internal view returns (bool) {
        return _isGlobalValidationAllowedNativeFunction(uint32(selector))
            || getAccountStorage().executionStorage[selector].allowGlobalValidation;
    }

    function _selectorValidationApplies(bytes4 selector, ValidationLookupKey validationFunction)
        internal
        view
        returns (bool)
    {
        return getAccountStorage().validationStorage[validationFunction].selectors.contains(toSetValue(selector));
    }

    function _domainSeparator() internal view returns (bytes32) {
        bytes32 result;

        // Compute the hash without permanently allocating memory
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, _DOMAIN_SEPARATOR_TYPEHASH)
            mstore(add(fmp, 0x20), chainid())
            mstore(add(fmp, 0x40), address())
            result := keccak256(fmp, 0x60)
        }

        return result;
    }

    // A virtual function to detect if a validation function is natively implemented. Used for determining call
    // buffer allocation.
    function _validationIsNative(ValidationLookupKey) internal pure virtual returns (bool) {
        return false;
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {ModuleEntity, ValidationConfig} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol";
import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

import {FALLBACK_VALIDATION_ID, FALLBACK_VALIDATION_LOOKUP_KEY} from "../helpers/Constants.sol";
import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SignatureType} from "../helpers/SignatureType.sol";
import {RTCallBuffer, SigCallBuffer, UOCallBuffer} from "../libraries/ExecutionLib.sol";
import {ValidationLocatorLib, ValidationLookupKey} from "../libraries/ValidationLocatorLib.sol";
import {ModularAccountBase} from "./ModularAccountBase.sol";

/// @title Semi-Modular Account Base
/// @author Alchemy
/// @notice Abstract base contract for the Alchemy Semi-Modular Account variants. Includes fallback signer
/// functionality.
/// @dev Inherits ModularAccountBase. Overrides certain functionality from ModularAccountBase, and exposes an
/// internal virtual getter for the fallback signer.
abstract contract SemiModularAccountBase is ModularAccountBase {
    using MessageHashUtils for bytes32;
    using ModuleEntityLib for ModuleEntity;
    using ValidationConfigLib for ValidationConfig;

    struct SemiModularAccountStorage {
        address fallbackSigner;
        bool fallbackSignerDisabled;
    }

    // keccak256("ReplaySafeHash(bytes32 hash)")
    bytes32 private constant _REPLAY_SAFE_HASH_TYPEHASH =
        0x294a8735843d4afb4f017c76faf3b7731def145ed0025fc9b1d5ce30adf113ff;

    // keccak256("ERC6900.SemiModularAccount.Storage")
    uint256 internal constant _SEMI_MODULAR_ACCOUNT_STORAGE_SLOT =
        0x5b9dc9aa943f8fa2653ceceda5e3798f0686455280432166ba472eca0bc17a32;

    uint256 internal constant _SIG_VALIDATION_PASSED = 0;
    uint256 internal constant _SIG_VALIDATION_FAILED = 1;

    event FallbackSignerUpdated(address indexed newFallbackSigner, bool isDisabled);

    error FallbackSignerMismatch();
    error FallbackValidationInstallationNotAllowed();
    error FallbackSignerDisabled();
    error InvalidSignatureType();

    constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
        ModularAccountBase(entryPoint, executionInstallDelegate)
    {}

    /// @notice Updates the fallback signer data in storage.
    /// @param fallbackSigner The new signer to set.
    /// @param isDisabled Whether to disable fallback signing entirely.
    function updateFallbackSignerData(address fallbackSigner, bool isDisabled) external wrapNativeFunction {
        SemiModularAccountStorage storage _storage = _getSemiModularAccountStorage();

        _storage.fallbackSigner = fallbackSigner;
        _storage.fallbackSignerDisabled = isDisabled;

        emit FallbackSignerUpdated(fallbackSigner, isDisabled);
    }

    function installValidation(
        ValidationConfig validationConfig,
        bytes4[] calldata selectors,
        bytes calldata installData,
        bytes[] calldata hooks
    ) external override wrapNativeFunction {
        // Previously, it was possible to "alias" the fallback validation by installing a module at the reserved
        // validation entity id 0. Not failing here could cause unexpected behavior, so this is checked to
        // explicitly revert and warn the caller that this operation would not do what is requested.
        //
        // Note that this state can still be reached by upgrading from MA to SMA, but should be handled with
        // initialization and de-init steps.
        if (validationConfig.entityId() == FALLBACK_VALIDATION_ID && validationConfig.module() != address(0)) {
            revert FallbackValidationInstallationNotAllowed();
        }
        _installValidation(validationConfig, selectors, installData, hooks);
    }

    /// @notice Returns the fallback signer data in storage.
    /// @return The fallback signer and a boolean, true if the fallback signer validation is disabled, false if it
    /// is enabled.
    function getFallbackSignerData() external view returns (address, bool) {
        SemiModularAccountStorage storage _storage = _getSemiModularAccountStorage();
        return (_retrieveFallbackSignerUnchecked(_storage), _storage.fallbackSignerDisabled);
    }

    function _execUserOpValidation(
        ValidationLookupKey validationLookupKey,
        bytes32 userOpHash,
        bytes calldata signatureSegment,
        UOCallBuffer callBuffer
    ) internal override returns (uint256) {
        if (validationLookupKey.eq(FALLBACK_VALIDATION_LOOKUP_KEY)) {
            address fallbackSigner = _getFallbackSigner();

            if (_checkSignature(fallbackSigner, userOpHash.toEthSignedMessageHash(), signatureSegment)) {
                return _SIG_VALIDATION_PASSED;
            }
            return _SIG_VALIDATION_FAILED;
        }

        return super._execUserOpValidation(validationLookupKey, userOpHash, signatureSegment, callBuffer);
    }

    function _execRuntimeValidation(
        ValidationLookupKey validationLookupKey,
        RTCallBuffer callBuffer,
        bytes calldata authorization
    ) internal override {
        if (validationLookupKey.eq(FALLBACK_VALIDATION_LOOKUP_KEY)) {
            address fallbackSigner = _getFallbackSigner();

            if (msg.sender != fallbackSigner) {
                revert FallbackSignerMismatch();
            }
        } else {
            super._execRuntimeValidation(validationLookupKey, callBuffer, authorization);
        }
    }

    function _exec1271Validation(
        SigCallBuffer buffer,
        bytes32 hash,
        ValidationLookupKey validationLookupKey,
        bytes calldata signature
    ) internal view override returns (bytes4) {
        if (validationLookupKey.eq(FALLBACK_VALIDATION_LOOKUP_KEY)) {
            address fallbackSigner = _getFallbackSigner();

            // If called during validateUserOp, this implies that we're doing a deferred validation installation.
            // In this case, as the hash is already replay-safe, we don't need to wrap it.
            if (msg.sig != this.validateUserOp.selector) {
                hash = _replaySafeHash(hash);
            }

            if (_checkSignature(fallbackSigner, hash, signature)) {
                return _1271_MAGIC_VALUE;
            }
            return _1271_INVALID;
        }
        return super._exec1271Validation(buffer, hash, validationLookupKey, signature);
    }

    function _checkSignature(address owner, bytes32 digest, bytes calldata sig) internal view returns (bool) {
        if (sig.length < 1) {
            revert InvalidSignatureType();
        }
        SignatureType sigType = SignatureType(uint8(bytes1(sig)));
        sig = sig[1:];
        if (sigType == SignatureType.EOA) {
            (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(digest, sig);
            if (err == ECDSA.RecoverError.NoError && recovered == owner) {
                return true;
            }
            return false;
        } else if (sigType == SignatureType.CONTRACT_OWNER) {
            return SignatureChecker.isValidERC1271SignatureNow(owner, digest, sig);
        }
        revert InvalidSignatureType();
    }

    function _isValidationGlobal(ValidationLookupKey validationFunction) internal view override returns (bool) {
        if (validationFunction.eq(FALLBACK_VALIDATION_LOOKUP_KEY) || super._isValidationGlobal(validationFunction))
        {
            return true;
        }

        // At this point, the validation is not the fallback, and it's not an installed global validation.
        SemiModularAccountStorage storage smaStorage = _getSemiModularAccountStorage();

        // Before checking direct-call validation, we return false if fallback validation is disabled.
        if (smaStorage.fallbackSignerDisabled) {
            return false;
        }

        // Retrieve the fallback signer.
        address fallbackSigner = _retrieveFallbackSignerUnchecked(smaStorage);

        // Compute the direct call validation key.
        ValidationLookupKey fallbackDirectCallValidation = ValidationLocatorLib.directCallLookupKey(fallbackSigner);

        // Return true if the validation function passed is the fallback direct call validation key, and the sender
        // is the fallback signer. This enforces that context is a
        return validationFunction.eq(fallbackDirectCallValidation) && msg.sender == fallbackSigner;
    }

    function _getFallbackSigner() internal view returns (address) {
        SemiModularAccountStorage storage _storage = _getSemiModularAccountStorage();

        if (_storage.fallbackSignerDisabled) {
            revert FallbackSignerDisabled();
        }

        // This can return zero.
        return _retrieveFallbackSignerUnchecked(_storage);
    }

    /// @dev SMA implementations must implement their own fallback signer getter.
    ///
    /// NOTE: The passed storage pointer may point to a struct with a zero address signer. It's up
    /// to inheritors to determine what to do with that information. No assumptions about storage
    /// state are safe to make besides layout.
    function _retrieveFallbackSignerUnchecked(SemiModularAccountStorage storage _storage)
        internal
        view
        virtual
        returns (address)
    {
        return _storage.fallbackSigner;
    }

    /// @notice Returns the replay-safe hash generated from the passed typed data hash for 1271 validation.
    /// @param hash The typed data hash to wrap in a replay-safe hash.
    /// @return The replay-safe hash, to be used for 1271 signature generation.
    ///
    /// @dev Generates a replay-safe hash to wrap a standard typed data hash. This prevents replay attacks by
    /// enforcing the domain separator, which includes this contract's address and the chainId. This is only
    /// relevant for 1271 validation because UserOp validation relies on the UO hash and the Entrypoint has
    /// safeguards.
    ///
    /// NOTE: Like in signature-based validation modules, the returned hash should be used to generate signatures,
    /// but the original hash should be passed to the external-facing function for 1271 validation.
    function _replaySafeHash(bytes32 hash) internal view returns (bytes32) {
        return MessageHashUtils.toTypedDataHash({
            domainSeparator: _domainSeparator(),
            structHash: _hashStructReplaySafeHash(hash)
        });
    }

    function _getSemiModularAccountStorage() internal pure returns (SemiModularAccountStorage storage) {
        SemiModularAccountStorage storage _storage;
        assembly ("memory-safe") {
            _storage.slot := _SEMI_MODULAR_ACCOUNT_STORAGE_SLOT
        }
        return _storage;
    }

    // Conditionally skip allocation of call buffers.
    function _validationIsNative(ValidationLookupKey validationLookupKey)
        internal
        pure
        virtual
        override
        returns (bool)
    {
        return validationLookupKey.eq(FALLBACK_VALIDATION_LOOKUP_KEY);
    }

    /// @notice Adds a EIP-712 replay safe hash wrapper to the digest
    /// @param hash The hash to wrap in a replay-safe hash
    /// @return The replay-safe hash
    function _hashStructReplaySafeHash(bytes32 hash) internal pure virtual returns (bytes32) {
        bytes32 res;
        assembly ("memory-safe") {
            mstore(0x00, _REPLAY_SAFE_HASH_TYPEHASH)
            mstore(0x20, hash)
            res := keccak256(0, 0x40)
        }
        return res;
    }

    /// @dev Overrides ModularAccountView.
    function _isNativeFunction(uint32 selector) internal pure virtual override returns (bool) {
        return super._isNativeFunction(selector) || selector == uint32(this.updateFallbackSignerData.selector)
            || selector == uint32(this.getFallbackSignerData.selector);
    }

    /// @dev Overrides ModularAccountView.
    function _isWrappedNativeFunction(uint32 selector) internal pure virtual override returns (bool) {
        return
            super._isWrappedNativeFunction(selector) || selector == uint32(this.updateFallbackSignerData.selector);
    }
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

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

struct ManifestExecutionFunction {
    // The selector to install
    bytes4 executionSelector;
    // If true, the function won't need runtime validation, and can be called by anyone.
    bool skipRuntimeValidation;
    // If true, the function can be validated by a global validation function.
    bool allowGlobalValidation;
}

struct ManifestExecutionHook {
    bytes4 executionSelector;
    uint32 entityId;
    bool isPreHook;
    bool isPostHook;
}

/// @dev A struct describing how the module should be installed on a modular account.
struct ExecutionManifest {
    // Execution functions defined in this module to be installed on the MSCA.
    ManifestExecutionFunction[] executionFunctions;
    ManifestExecutionHook[] executionHooks;
    // List of ERC-165 interface IDs to add to account to support introspection checks. This MUST NOT include
    // IModule's interface ID.
    bytes4[] interfaceIds;
}

interface IExecutionModule is IModule {
    /// @notice Describe the contents and intended configuration of the module.
    /// @dev This manifest MUST stay constant over time.
    /// @return A manifest describing the contents and intended configuration of the module.
    function executionManifest() external pure returns (ExecutionManifest memory);
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

interface IModule is IERC165 {
    /// @notice Initialize module data for the modular account.
    /// @dev Called by the modular account during `installExecution`.
    /// @param data Optional bytes array to be decoded and used by the module to setup initial module data for the
    /// modular account.
    function onInstall(bytes calldata data) external;

    /// @notice Clear module data for the modular account.
    /// @dev Called by the modular account during `uninstallExecution`.
    /// @param data Optional bytes array to be decoded and used by the module to clear module data for the modular
    /// account.
    function onUninstall(bytes calldata data) external;

    /// @notice Return a unique identifier for the module.
    /// @dev This function MUST return a string in the format "vendor.module.semver". The vendor and module
    /// names MUST NOT contain a period character.
    /// @return The module ID.
    function moduleId() external view returns (string memory);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import {HookConfig, ModuleEntity} from "../interfaces/IModularAccount.sol";

// Hook types:
// Exec hook: bools for hasPre, hasPost
// Validation hook: no bools

// Hook fields:
// module address
// entity ID
// hook type
// if exec hook: hasPre, hasPost

// Hook config is a packed representation of a hook function and flags for its configuration.
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________CC______________ // Hook Flags

// Hook flags layout:
// 0b00000___ // unused
// 0b_____A__ // hasPre (exec only)
// 0b______B_ // hasPost (exec only)
// 0b_______C // hook type (0 for exec, 1 for validation)

library HookConfigLib {
    // Hook type constants
    // Exec has no bits set
    bytes32 internal constant _HOOK_TYPE_EXEC = bytes32(uint256(0));
    // Validation has 1 in the 25th byte
    bytes32 internal constant _HOOK_TYPE_VALIDATION = bytes32(uint256(1) << 56);

    // Exec hook flags constants
    // Pre hook has 1 in 4's bit in the 25th byte
    bytes32 internal constant _EXEC_HOOK_HAS_PRE = bytes32(uint256(1) << 58);
    // Post hook has 1 in 2's bit in the 25th byte
    bytes32 internal constant _EXEC_HOOK_HAS_POST = bytes32(uint256(1) << 57);

    function packValidationHook(ModuleEntity _hookFunction) internal pure returns (HookConfig) {
        return
            HookConfig.wrap(bytes25(bytes25(ModuleEntity.unwrap(_hookFunction)) | bytes25(_HOOK_TYPE_VALIDATION)));
    }

    function packValidationHook(address _module, uint32 _entityId) internal pure returns (HookConfig) {
        return HookConfig.wrap(
            bytes25(
                // module address stored in the first 20 bytes
                bytes25(bytes20(_module))
                // entityId stored in the 21st - 24th byte
                | bytes25(bytes24(uint192(_entityId))) | bytes25(_HOOK_TYPE_VALIDATION)
            )
        );
    }

    function packExecHook(ModuleEntity _hookFunction, bool _hasPre, bool _hasPost)
        internal
        pure
        returns (HookConfig)
    {
        return HookConfig.wrap(
            bytes25(
                bytes25(ModuleEntity.unwrap(_hookFunction))
                // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0
                | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0))
                    | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0))
            )
        );
    }

    function packExecHook(address _module, uint32 _entityId, bool _hasPre, bool _hasPost)
        internal
        pure
        returns (HookConfig)
    {
        return HookConfig.wrap(
            bytes25(
                // module address stored in the first 20 bytes
                bytes25(bytes20(_module))
                // entityId stored in the 21st - 24th byte
                | bytes25(bytes24(uint192(_entityId)))
                // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0
                | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0))
                    | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0))
            )
        );
    }

    function unpackValidationHook(HookConfig _config) internal pure returns (ModuleEntity _hookFunction) {
        bytes25 configBytes = HookConfig.unwrap(_config);
        _hookFunction = ModuleEntity.wrap(bytes24(configBytes));
    }

    function unpackExecHook(HookConfig _config)
        internal
        pure
        returns (ModuleEntity _hookFunction, bool _hasPre, bool _hasPost)
    {
        bytes25 configBytes = HookConfig.unwrap(_config);
        _hookFunction = ModuleEntity.wrap(bytes24(configBytes));
        _hasPre = configBytes & _EXEC_HOOK_HAS_PRE != 0;
        _hasPost = configBytes & _EXEC_HOOK_HAS_POST != 0;
    }

    function module(HookConfig _config) internal pure returns (address) {
        return address(bytes20(HookConfig.unwrap(_config)));
    }

    function entityId(HookConfig _config) internal pure returns (uint32) {
        return uint32(bytes4(HookConfig.unwrap(_config) << 160));
    }

    function moduleEntity(HookConfig _config) internal pure returns (ModuleEntity) {
        return ModuleEntity.wrap(bytes24(HookConfig.unwrap(_config)));
    }

    // Check if the hook is a validation hook
    // If false, it is an exec hook
    function isValidationHook(HookConfig _config) internal pure returns (bool) {
        return HookConfig.unwrap(_config) & _HOOK_TYPE_VALIDATION != 0;
    }

    // Check if the exec hook has a pre hook
    // Undefined behavior if the hook is not an exec hook
    function hasPreHook(HookConfig _config) internal pure returns (bool) {
        return HookConfig.unwrap(_config) & _EXEC_HOOK_HAS_PRE != 0;
    }

    // Check if the exec hook has a post hook
    // Undefined behavior if the hook is not an exec hook
    function hasPostHook(HookConfig _config) internal pure returns (bool) {
        return HookConfig.unwrap(_config) & _EXEC_HOOK_HAS_POST != 0;
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {HookConfig, ValidationFlags} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";

import {LinkedListSet, SetValue} from "../libraries/LinkedListSetLib.sol";
import {ValidationLookupKey} from "../libraries/ValidationLocatorLib.sol";

// ERC-7201 derived storage slot.
// keccak256(abi.encode(uint256(keccak256("Alchemy.ModularAccount.Storage_V2")) - 1)) & ~bytes32(uint256(0xff))
bytes32 constant _ACCOUNT_STORAGE_SLOT = 0x596912a710dec01bac203cb0ed2c7e56a2ce6b2a68276967fff6dd57561bdd00;

/// @notice Represents data associated with a specific function selector.
struct ExecutionStorage {
    // The module that implements this execution function.
    // If this is a native function, the address should remain address(0).
    address module;
    // Whether or not the function needs runtime validation, or can be called without any validation. The function
    // can still be state changing if this flag is set to true.
    // Note that even if this is set to true, user op validation will still be required, otherwise any caller could
    // drain the account of native tokens by wasting gas.
    bool skipRuntimeValidation;
    // Whether or not a global validation function may be used to validate this function.
    bool allowGlobalValidation;
    // The execution hooks for this function selector.
    LinkedListSet executionHooks;
}

/// @notice Represents data associated with a specific validation function.
struct ValidationStorage {
    // The address of the validation module.
    address module;
    // ValidationFlags layout:
    // 0b00000___ // unused
    // 0b_____A__ // isGlobal
    // 0b______B_ // isSignatureValidation
    // 0b_______C // isUserOpValidation
    ValidationFlags validationFlags;
    // Length of the validation hooks for this validation function. The length is stored here, in the same storage
    // slot as the flags, to save an `sload` when putting the hooks into memory.
    uint8 validationHookCount;
    // Length of execution hooks for this validation function. The length is stored here, in the same storage slot
    // as the flags, to save an `sload` when putting the hooks into memory.
    uint8 executionHookCount;
    // The validation hooks for this validation function.
    LinkedListSet validationHooks;
    // Execution hooks to run with this validation function.
    LinkedListSet executionHooks;
    // The set of selectors that may be validated by this validation function.
    LinkedListSet selectors;
}

/// @custom:storage-location erc7201:Alchemy.ModularAccount.Storage_V2
struct AccountStorage {
    // AccountStorageInitializable variables.
    uint64 initialized;
    bool initializing;
    // Execution functions and their associated functions.
    mapping(bytes4 selector => ExecutionStorage) executionStorage;
    // Validation functions and their associated functions.
    mapping(ValidationLookupKey lookupKey => ValidationStorage) validationStorage;
    // Module-defined ERC-165 interfaces installed on the account.
    mapping(bytes4 => uint256) supportedIfaces;
}

function getAccountStorage() pure returns (AccountStorage storage _storage) {
    assembly ("memory-safe") {
        _storage.slot := _ACCOUNT_STORAGE_SLOT
    }
}

function toSetValue(HookConfig hookConfig) pure returns (SetValue) {
    return SetValue.wrap(bytes31(HookConfig.unwrap(hookConfig)));
}

function toSetValue(bytes4 selector) pure returns (SetValue) {
    return SetValue.wrap(bytes31(selector));
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol";
import {IExecutionModule} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol";
import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol";
import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol";
import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol";
import {IAggregator} from "@eth-infinitism/account-abstraction/interfaces/IAggregator.sol";
import {IPaymaster} from "@eth-infinitism/account-abstraction/interfaces/IPaymaster.sol";

/// @title Known Selectors Library
/// @author Alchemy
/// @notice Library to help to check if a selector is an ERC-6900 module function or a an ERC-4337 contract
/// function.
library KnownSelectorsLib {
    /// @notice Check if a selector is an ERC-4337 function.
    /// @param selector The selector to check.
    /// @return True if the selector is an ERC-4337 function, false otherwise.
    function isERC4337Function(uint32 selector) internal pure returns (bool) {
        return selector == uint32(IAggregator.validateSignatures.selector)
            || selector == uint32(IAggregator.validateUserOpSignature.selector)
            || selector == uint32(IAggregator.aggregateSignatures.selector)
            || selector == uint32(IPaymaster.validatePaymasterUserOp.selector)
            || selector == uint32(IPaymaster.postOp.selector);
    }

    /// @notice Check if a selector is an ERC-6900 module function.
    /// @param selector The selector to check.
    /// @return True if the selector is an ERC-6900 module function, false otherwise.
    function isIModuleFunction(uint32 selector) internal pure returns (bool) {
        return selector == uint32(IModule.onInstall.selector) || selector == uint32(IModule.onUninstall.selector)
            || selector == uint32(IModule.moduleId.selector)
            || selector == uint32(IExecutionModule.executionManifest.selector)
            || selector == uint32(IExecutionHookModule.preExecutionHook.selector)
            || selector == uint32(IExecutionHookModule.postExecutionHook.selector)
            || selector == uint32(IValidationModule.validateUserOp.selector)
            || selector == uint32(IValidationModule.validateRuntime.selector)
            || selector == uint32(IValidationModule.validateSignature.selector)
            || selector == uint32(IValidationHookModule.preUserOpValidationHook.selector)
            || selector == uint32(IValidationHookModule.preRuntimeValidationHook.selector)
            || selector == uint32(IValidationHookModule.preSignatureValidationHook.selector);
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

type SetValue is bytes31;

/// @dev The sentinel value is used to indicate the head and tail of the list.
bytes32 constant SENTINEL_VALUE = bytes32(uint256(1));

struct LinkedListSet {
    // Byte Layout
    // | value | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__ |
    // | meta  | 0x______________________________________________________________BB |

    // Bit-layout of the meta byte
    // | unused   | 0b0000000_ |
    // | sentinel | 0b_______A |

    // Key excludes the meta bytes, except for the sentinel value, which is 0x1
    mapping(bytes32 => bytes32) map;
}

/// @title Linked List Set Library
/// @author Alchemy
/// @notice This library provides a set of functions for managing enumerable sets of bytes31 values. It is a fork
/// of the LinkedListSet library in modular-account-libs, with the following changes:
/// - The flags feature has been removed, so the library no longer supports both the "has next" flag, and the
/// user-defined flags.
/// - The library has been modified to work with bytes31 values instead of bytes30 values.
library LinkedListSetLib {
    /// @notice Add a value to a set.
    /// @param set The set to add the value to.
    /// @param value The value to add.
    /// @return True if the value was added, false if the value cannot be added (already exists or is zero).
    function tryAdd(LinkedListSet storage set, SetValue value) internal returns (bool) {
        mapping(bytes32 => bytes32) storage map = set.map;
        bytes32 unwrappedKey = SetValue.unwrap(value);
        if (unwrappedKey == bytes32(0) || map[unwrappedKey] != bytes32(0)) return false;

        bytes32 prev = map[SENTINEL_VALUE];
        if (prev == bytes32(0) || isSentinel(prev)) {
            // Set is empty
            map[SENTINEL_VALUE] = unwrappedKey;
            map[unwrappedKey] = SENTINEL_VALUE;
        } else {
            // set is not empty
            map[SENTINEL_VALUE] = unwrappedKey;
            map[unwrappedKey] = prev;
        }

        return true;
    }

    /// @notice Remove a value from a set.
    /// @dev This is an O(n) operation, where n is the number of elements in the set.
    /// @param set The set to remove the value from.
    /// @param value The value to remove.
    /// @return True if the value was removed, false if the value does not exist.
    function tryRemove(LinkedListSet storage set, SetValue value) internal returns (bool) {
        mapping(bytes32 => bytes32) storage map = set.map;
        bytes32 unwrappedKey = SetValue.unwrap(value);

        bytes32 nextValue = map[unwrappedKey];
        if (unwrappedKey == bytes32(0) || nextValue == bytes32(0)) return false;

        bytes32 prevKey = SENTINEL_VALUE;
        bytes32 currentKey;
        do {
            currentKey = map[prevKey];
            if (currentKey == unwrappedKey) {
                // Set the previous value's next value to the next value,
                // and the flags to the current value's flags.
                // and the next value's `hasNext` flag to determine whether or not the next value is (or points to)
                // the sentinel value.
                map[prevKey] = nextValue;
                map[currentKey] = bytes32(0);

                return true;
            }
            prevKey = currentKey;
        } while (!isSentinel(currentKey) && currentKey != bytes32(0));
        return false;
    }

    /// @notice Remove a value from a set, given the previous value in the set.
    /// @dev This is an O(1) operation but requires additional knowledge.
    /// @param set The set to remove the value from.
    /// @param value The value to remove.
    /// @param prev The previous value in the set.
    /// @return True if the value was removed, false if the value does not exist, or if the wrong prev was
    /// specified.
    function tryRemoveKnown(LinkedListSet storage set, SetValue value, bytes32 prev) internal returns (bool) {
        mapping(bytes32 => bytes32) storage map = set.map;
        bytes32 unwrappedKey = SetValue.unwrap(value);

        if (prev == bytes32(0) || unwrappedKey == bytes32(0)) {
            return false;
        }

        // assert that the previous value's next value is the value to be removed
        bytes32 currentValue = map[prev];
        if (currentValue != unwrappedKey) {
            return false;
        }

        bytes32 next = map[unwrappedKey];
        if (next == bytes32(0)) {
            // The set didn't actually contain the value
            return false;
        }

        map[prev] = next;
        map[unwrappedKey] = bytes32(0);
        return true;
    }

    /// @notice Remove all values from a set.
    /// @dev This is an O(n) operation, where n is the number of elements in the set.
    /// @param set The set to remove the values from.
    function clear(LinkedListSet storage set) internal {
        mapping(bytes32 => bytes32) storage map = set.map;
        bytes32 cursor = SENTINEL_VALUE;

        do {
            bytes32 next = map[cursor];
            map[cursor] = bytes32(0);
            cursor = next;
        } while (!isSentinel(cursor) && cursor != bytes32(0));
    }

    /// @notice Check if a set contains a value.
    /// @dev This method does not clear the upper bits of `value`, that is expected to be done as part of casting
    /// to the correct type. If this function is provided the sentinel value by using the upper bits, this function
    /// may returns `true`.
    /// @param set The set to check.
    /// @param value The value to check for.
    /// @return True if the set contains the value, false otherwise.
    function contains(LinkedListSet storage set, SetValue value) internal view returns (bool) {
        mapping(bytes32 => bytes32) storage map = set.map;
        return map[SetValue.unwrap(value)] != bytes32(0);
    }

    /// @notice Check if a set is empty.
    /// @param set The set to check.
    /// @return True if the set is empty, false otherwise.
    function isEmpty(LinkedListSet storage set) internal view returns (bool) {
        mapping(bytes32 => bytes32) storage map = set.map;
        bytes32 val = map[SENTINEL_VALUE];
        return val == bytes32(0) || isSentinel(val); // either the sentinel is unset, or points to itself
    }

    /// @notice Get all elements in a set.
    /// @dev This is an O(n) operation, where n is the number of elements in the set.
    /// @param set The set to get the elements of.
    /// @return ret An array of all elements in the set.
    function getAll(LinkedListSet storage set) internal view returns (SetValue[] memory ret) {
        mapping(bytes32 => bytes32) storage map = set.map;
        uint256 size;
        bytes32 cursor = map[SENTINEL_VALUE];

        // Dynamically allocate the returned array as we iterate through the set, since we don't know the size
        // beforehand.
        // This is accomplished by first writing to memory after the free memory pointer,
        // then updating the free memory pointer to cover the newly-allocated data.
        // To the compiler, writes to memory after the free memory pointer are considered "memory safe".
        // See https://docs.soliditylang.org/en/v0.8.22/assembly.html#memory-safety
        // Stack variable lifting done when compiling with via-ir will only ever place variables into memory
        // locations below the current free memory pointer, so it is safe to compile this library with via-ir.
        // See https://docs.soliditylang.org/en/v0.8.22/yul.html#memoryguard
        assembly ("memory-safe") {
            // It is critical that no other memory allocations occur between:
            // -  loading the value of the free memory pointer into `ret`
            // -  updating the free memory pointer to point to the newly-allocated data, which is done after all
            // the values have been written.
            ret := mload(0x40)
        }

        while (!isSentinel(cursor) && cursor != bytes32(0)) {
            unchecked {
                ++size;
            }
            // Place the item into the return array manually. Since the size was just incremented, it will point to
            // the next location to write to.
            assembly ("memory-safe") {
                mstore(add(ret, mul(size, 0x20)), cursor)
            }

            cursor = map[cursor];
        }

        assembly ("memory-safe") {
            // Update the free memory pointer with the now-known length of the array.
            mstore(0x40, add(ret, mul(add(size, 1), 0x20)))
            // Set the length of the array.
            mstore(ret, size)
        }
    }

    function isSentinel(bytes32 value) internal pure returns (bool ret) {
        assembly ("memory-safe") {
            ret := and(value, 1)
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

import {toSetValue} from "../account/AccountStorage.sol";
import {ExecutionLib} from "./ExecutionLib.sol";
import {LinkedListSet, LinkedListSetLib} from "./LinkedListSetLib.sol";

/// @title Module Install Commons Library
/// @author Alchemy
/// @notice This is an internal library which holds module installation-related functions relevant to both the
/// ExecutionInstallDelegate and the ModuleManagerInternals contracts.
library ModuleInstallCommonsLib {
    using LinkedListSetLib for LinkedListSet;

    error InterfaceNotSupported(address module);
    error ModuleInstallCallbackFailed(address module, bytes revertReason);
    error ExecutionHookAlreadySet(HookConfig hookConfig);

    // Internal Functions

    // We don't need to bring the exec hook removal function here since it's only ever used in the
    // ExecutionInstallLib

    /// @dev adds an execution hook to a specific set of hooks.
    function addExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal {
        if (!hooks.tryAdd(toSetValue(hookConfig))) {
            revert ExecutionHookAlreadySet(hookConfig);
        }
    }

    /// @dev setup the module storage for the account, reverts are bubbled up into a custom
    /// ModuleInstallCallbackFailed
    function onInstall(address module, bytes calldata data, bytes4 interfaceId) internal {
        if (data.length > 0) {
            if (!ERC165Checker.supportsERC165InterfaceUnchecked(module, interfaceId)) {
                revert InterfaceNotSupported(module);
            }
            // solhint-disable-next-line no-empty-blocks
            try IModule(module).onInstall(data) {}
            catch {
                bytes memory revertReason = ExecutionLib.collectReturnData();
                revert ModuleInstallCallbackFailed(module, revertReason);
            }
        }
    }

    /// @dev clear the module storage for the account, reverts are IGNORED. Status is included in emitted event.
    function onUninstall(address module, bytes calldata data) internal returns (bool onUninstallSuccess) {
        onUninstallSuccess = true;
        if (data.length > 0) {
            // Clear the module storage for the account.
            // solhint-disable-next-line no-empty-blocks
            try IModule(module).onUninstall(data) {}
            catch {
                onUninstallSuccess = false;
            }
        }
    }
}

File 29 of 70 : EmptyCalldataSlice.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

function getEmptyCalldataSlice() pure returns (bytes calldata) {
    bytes calldata empty;

    assembly ("memory-safe") {
        empty.length := 0
    }

    return empty;
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import {ModuleEntity} from "../interfaces/IModularAccount.sol";
// ModuleEntity is a packed representation of a module function
// Layout:
// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address
// 0x________________________________________BBBBBBBB________________ // Entity ID
// 0x________________________________________________0000000000000000 // unused

library ModuleEntityLib {
    function pack(address addr, uint32 entityId) internal pure returns (ModuleEntity) {
        return ModuleEntity.wrap(bytes24(bytes20(addr)) | bytes24(uint192(entityId)));
    }

    function unpack(ModuleEntity moduleEntity) internal pure returns (address addr, uint32 entityId) {
        bytes24 underlying = ModuleEntity.unwrap(moduleEntity);
        addr = address(bytes20(underlying));
        entityId = uint32(bytes4(underlying << 160));
    }

    function isEmpty(ModuleEntity moduleEntity) internal pure returns (bool) {
        return ModuleEntity.unwrap(moduleEntity) == bytes24(0);
    }

    function notEmpty(ModuleEntity moduleEntity) internal pure returns (bool) {
        return ModuleEntity.unwrap(moduleEntity) != bytes24(0);
    }

    function eq(ModuleEntity a, ModuleEntity b) internal pure returns (bool) {
        return ModuleEntity.unwrap(a) == ModuleEntity.unwrap(b);
    }

    function notEq(ModuleEntity a, ModuleEntity b) internal pure returns (bool) {
        return ModuleEntity.unwrap(a) != ModuleEntity.unwrap(b);
    }
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import {RESERVED_VALIDATION_DATA_INDEX} from "../helpers/Constants.sol";
import {getEmptyCalldataSlice} from "../helpers/EmptyCalldataSlice.sol";

/// @title Sparse Calldata Segment Library
/// @notice Library for working with sparsely-packed calldata segments, identified with an index.
/// @dev The first byte of each segment is the index of the segment.
/// To prevent accidental stack-to-deep errors, the body and index of the segment are extracted separately, rather
/// than inline as part of the tuple returned by `getNextSegment`.
library SparseCalldataSegmentLib {
    error NonCanonicalEncoding();
    error SegmentOutOfOrder();
    error ValidationSignatureSegmentMissing();

    /// @notice Splits out a segment of calldata, sparsely-packed.
    /// The expected format is:
    /// [uint8(index0), uint32(len(segment0)), segment0, uint8(index1), uint32(len(segment1)), segment1,
    /// ... uint8(indexN), uint32(len(segmentN)), segmentN]
    /// @param source The calldata to extract the segment from.
    /// @return segment The extracted segment. Using the above example, this would be segment0.
    /// @return remainder The remaining calldata. Using the above example,
    /// this would start at uint8(index1) and continue to the end at segmentN.
    function getNextSegment(bytes calldata source)
        internal
        pure
        returns (bytes calldata segment, bytes calldata remainder)
    {
        // The first byte of the segment is the index.
        // The next 4 bytes hold the length of the segment, excluding the index.
        uint32 length = uint32(bytes4(source[1:5]));

        // The offset of the remainder of the calldata.
        uint256 remainderOffset = 5 + length;

        // The segment is the next `length` bytes after the first 5 bytes.
        segment = source[5:remainderOffset];

        // The remainder is the rest of the calldata.
        remainder = source[remainderOffset:];
    }

    /// @notice If the index of the next segment in the source equals the provided index, return the next body and
    /// advance the source by one segment.
    /// @dev Reverts if the index of the next segment is less than the provided index, or if the extracted segment
    /// has length 0.
    /// @param source The calldata to extract the segment from.
    /// @param index The index of the segment to extract.
    /// @return A tuple containing the extracted segment's body, or an empty buffer if the index is not found, and
    /// the remaining calldata.
    function advanceSegmentIfAtIndex(bytes calldata source, uint8 index)
        internal
        pure
        returns (bytes calldata, bytes calldata)
    {
        uint8 nextIndex = getIndex(source);

        if (nextIndex < index) {
            revert SegmentOutOfOrder();
        }

        if (nextIndex == index) {
            (bytes calldata segment, bytes calldata remainder) = getNextSegment(source);

            if (segment.length == 0) {
                revert NonCanonicalEncoding();
            }

            return (segment, remainder);
        }

        return (getEmptyCalldataSlice(), source);
    }

    /// @notice Extracts the final segment from the source.
    /// @dev Reverts if the index of the segment is not RESERVED_VALIDATION_DATA_INDEX.
    /// @param source The calldata to extract the segment from.
    /// @return The final segment.
    function getFinalSegment(bytes calldata source) internal pure returns (bytes calldata) {
        if (getIndex(source) != RESERVED_VALIDATION_DATA_INDEX) {
            revert ValidationSignatureSegmentMissing();
        }

        return source[1:];
    }

    /// @notice Extracts the index from a segment.
    /// @dev The first byte of the segment is the index.
    /// @param segment The segment to extract the index from
    /// @return The index of the segment
    function getIndex(bytes calldata segment) internal pure returns (uint8) {
        return uint8(segment[0]);
    }
}

File 32 of 70 : IAccountExecute.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

import "./PackedUserOperation.sol";

interface IAccountExecute {
    /**
     * Account may implement this execute method.
     * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash)
     * to the account.
     * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields)
     *
     * @param userOp              - The operation that was just validated.
     * @param userOpHash          - Hash of the user's request data.
     */
    function executeUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash
    ) external;
}

File 33 of 70 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 35 of 70 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

/// @notice UUPS proxy mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol)
/// @author Modified from OpenZeppelin
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol)
///
/// @dev Note:
/// - This implementation is intended to be used with ERC1967 proxies.
/// See: `LibClone.deployERC1967` and related functions.
/// - This implementation is NOT compatible with legacy OpenZeppelin proxies
/// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`.
abstract contract UUPSUpgradeable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The upgrade failed.
    error UpgradeFailed();

    /// @dev The call is from an unauthorized call context.
    error UnauthorizedCallContext();

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

    /// @dev For checking if the context is a delegate call.
    uint256 private immutable __self = uint256(uint160(address(this)));

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

    /// @dev Emitted when the proxy's implementation is upgraded.
    event Upgraded(address indexed implementation);

    /// @dev `keccak256(bytes("Upgraded(address)"))`.
    uint256 private constant _UPGRADED_EVENT_SIGNATURE =
        0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b;

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

    /// @dev The ERC-1967 storage slot for the implementation in the proxy.
    /// `uint256(keccak256("eip1967.proxy.implementation")) - 1`.
    bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

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

    /// @dev Please override this function to check if `msg.sender` is authorized
    /// to upgrade the proxy to `newImplementation`, reverting if not.
    /// ```
    ///     function _authorizeUpgrade(address) internal override onlyOwner {}
    /// ```
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /// @dev Returns the storage slot used by the implementation,
    /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822).
    ///
    /// Note: The `notDelegated` modifier prevents accidental upgrades to
    /// an implementation that is a proxy contract.
    function proxiableUUID() public view virtual notDelegated returns (bytes32) {
        // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967.
        return _ERC1967_IMPLEMENTATION_SLOT;
    }

    /// @dev Upgrades the proxy's implementation to `newImplementation`.
    /// Emits a {Upgraded} event.
    ///
    /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`.
    function upgradeToAndCall(address newImplementation, bytes calldata data)
        public
        payable
        virtual
        onlyProxy
    {
        _authorizeUpgrade(newImplementation);
        /// @solidity memory-safe-assembly
        assembly {
            newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits.
            mstore(0x01, 0x52d1902d) // `proxiableUUID()`.
            let s := _ERC1967_IMPLEMENTATION_SLOT
            // Check if `newImplementation` implements `proxiableUUID` correctly.
            if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) {
                mstore(0x01, 0x55299b49) // `UpgradeFailed()`.
                revert(0x1d, 0x04)
            }
            // Emit the {Upgraded} event.
            log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation)
            sstore(s, newImplementation) // Updates the implementation.

            // Perform a delegatecall to `newImplementation` if `data` is non-empty.
            if data.length {
                // Forwards the `data` to `newImplementation` via delegatecall.
                let m := mload(0x40)
                calldatacopy(m, data.offset, data.length)
                if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00))
                {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
        }
    }

    /// @dev Requires that the execution is performed through a proxy.
    modifier onlyProxy() {
        uint256 s = __self;
        /// @solidity memory-safe-assembly
        assembly {
            // To enable use cases with an immutable default implementation in the bytecode,
            // (see: ERC6551Proxy), we don't require that the proxy address must match the
            // value stored in the implementation slot, which may not be initialized.
            if eq(s, address()) {
                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }

    /// @dev Requires that the execution is NOT performed via delegatecall.
    /// This is the opposite of `onlyProxy`.
    modifier notDelegated() {
        uint256 s = __self;
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(eq(s, address())) {
                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

File 39 of 70 : ValidationResHelpers.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

// solhint-disable-next-line private-vars-leading-underscore
function _coalescePreValidation(uint256 validationRes1, uint256 validationRes2)
    pure
    returns (uint256 resValidationData)
{
    resValidationData = _coalesceValidationResTime(validationRes1, validationRes2);

    // Once we know that the authorizer field is 0 or 1, we can safely bubble up SIG_FAIL with bitwise OR
    resValidationData |= uint160(validationRes1) | uint160(validationRes2);
}

// solhint-disable-next-line private-vars-leading-underscore
function _coalesceValidation(uint256 preValidationData, uint256 validationRes)
    pure
    returns (uint256 resValidationData)
{
    resValidationData = _coalesceValidationResTime(preValidationData, validationRes);

    // If prevalidation failed, bubble up failure, and ignore authorizer
    resValidationData |= uint160(preValidationData) == 1 ? 1 : uint160(validationRes);
}

// solhint-disable-next-line private-vars-leading-underscore
function _coalesceValidationResTime(uint256 validationRes1, uint256 validationRes2)
    pure
    returns (uint256 resValidationData)
{
    uint48 validUntil1 = uint48(validationRes1 >> 160);
    if (validUntil1 == 0) {
        validUntil1 = type(uint48).max;
    }
    uint48 validUntil2 = uint48(validationRes2 >> 160);
    if (validUntil2 == 0) {
        validUntil2 = type(uint48).max;
    }
    resValidationData = ((validUntil1 > validUntil2) ? uint256(validUntil2) << 160 : uint256(validUntil1) << 160);

    uint48 validAfter1 = uint48(validationRes1 >> 208);
    uint48 validAfter2 = uint48(validationRes2 >> 208);

    resValidationData |= ((validAfter1 < validAfter2) ? uint256(validAfter2) << 208 : uint256(validAfter1) << 208);
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

interface IModularAccountBase {
    /// @notice Create a contract.
    /// @param value The value to send to the new contract constructor
    /// @param initCode The initCode to deploy.
    /// @param isCreate2 The bool to indicate which method to use to deploy.
    /// @param salt The salt for deployment.
    /// @return createdAddr The created contract address.
    function performCreate(uint256 value, bytes calldata initCode, bool isCreate2, bytes32 salt)
        external
        payable
        returns (address createdAddr);
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol";
import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccountView.sol";
import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol";
import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol";
import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol";
import {ModuleEntity} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

// The following types alias a `bytes memory`, to protect the user from doing anything unexpected with it. We can't
// actually alias a `bytes memory` type, so we use a `bytes32` type instead, and cast it to `bytes memory` within
// this library.
type UOCallBuffer is bytes32;

type RTCallBuffer is bytes32;

type PHCallBuffer is bytes32;

type SigCallBuffer is bytes32;

type DensePostHookData is bytes32;

using HookConfigLib for HookConfig;

/// @title Execution Library
/// @author Alchemy
/// @notice A library for performing external calls. This library is used for the external calls of `execute` and
/// `executeBatch`, for any account self-calls, and for any call to a module function.
/// @dev This library uses "call buffers", or reusable memory buffers that hold the abi-encoded data to be sent to
/// a module function. These buffers are used to avoid the overhead of encoding the same data multiple times.
library ExecutionLib {
    // solhint-disable ordering
    // Functions are more readable in original order.

    error PostExecHookReverted(ModuleEntity moduleFunction, bytes revertReason);
    error PreExecHookReverted(ModuleEntity moduleFunction, bytes revertReason);
    error PreRuntimeValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason);
    error PreSignatureValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason);
    error PreUserOpValidationHookReverted(ModuleEntity moduleFunction, bytes revertReason);
    error RuntimeValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason);
    error SignatureValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason);
    error UserOpValidationFunctionReverted(ModuleEntity moduleFunction, bytes revertReason);

    /// @notice Perform the following call, without capturing any return data.
    /// If the call reverts, the revert message will be directly bubbled up.
    /// @param target The address to call.
    /// @param value The value to send with the call.
    /// @param callData The data to send with the call.
    function callBubbleOnRevert(address target, uint256 value, bytes memory callData) internal {
        // Manually call, without collecting return data unless there's a revert.
        assembly ("memory-safe") {
            let success :=
                call(
                    gas(),
                    target,
                    /*value*/
                    value,
                    /*argOffset*/
                    add(callData, 0x20),
                    /*argSize*/
                    mload(callData),
                    /*retOffset*/
                    codesize(),
                    /*retSize*/
                    0
                )

            // directly bubble up revert messages, if any.
            if iszero(success) {
                // For memory safety, copy this revert data to scratch space past the end of used memory. Because
                // we immediately revert, we can omit storing the length as we normally would for a `bytes memory`
                // type, as well as omit finalizing the allocation by updating the free memory pointer.
                let revertDataLocation := mload(0x40)
                returndatacopy(revertDataLocation, 0, returndatasize())
                revert(revertDataLocation, returndatasize())
            }
        }
    }

    /// @notice Transiently copy the call data to a memory, and perform a self-call.
    /// If the call reverts, the revert message will be directly bubbled up.
    /// @param target The address to call.
    /// @param value The value to send with the call.
    /// @param callData The data to send with the call.
    function callBubbleOnRevertTransient(address target, uint256 value, bytes calldata callData) internal {
        bytes memory encodedCall;

        assembly ("memory-safe") {
            // Store the length of the call
            encodedCall := mload(0x40)
            mstore(encodedCall, callData.length)
            // Copy in the calldata
            calldatacopy(add(encodedCall, 0x20), callData.offset, callData.length)
        }

        callBubbleOnRevert(target, value, encodedCall);
        // Memory is discarded afterwards
    }

    // Transiently copy the call data to a memory, and perform a self-call.
    function delegatecallBubbleOnRevertTransient(address target) internal {
        assembly ("memory-safe") {
            // Store the length of the call
            let fmp := mload(0x40)

            // Copy in the entire calldata
            calldatacopy(fmp, 0, calldatasize())

            let success :=
                delegatecall(
                    gas(),
                    target,
                    /*argOffset*/
                    fmp,
                    /*argSize*/
                    calldatasize(),
                    /*retOffset*/
                    codesize(),
                    /*retSize*/
                    0
                )

            // directly bubble up revert messages, if any.
            if iszero(success) {
                // For memory safety, copy this revert data to scratch space past the end of used memory. Because
                // we immediately revert, we can omit storing the length as we normally would for a `bytes memory`
                // type, as well as omit finalizing the allocation by updating the free memory pointer.
                let revertDataLocation := mload(0x40)
                returndatacopy(revertDataLocation, 0, returndatasize())
                revert(revertDataLocation, returndatasize())
            }
        }
        // Memory is discarded afterwards
    }

    /// @notice Manually collect and store the return data from the most recent external call into a `bytes
    /// memory`.
    /// @return returnData The return data from the most recent external call.
    function collectReturnData() internal pure returns (bytes memory returnData) {
        assembly ("memory-safe") {
            // Allocate a buffer of that size, advancing the memory pointer to the nearest word
            returnData := mload(0x40)
            mstore(returnData, returndatasize())
            mstore(0x40, and(add(add(returnData, returndatasize()), 0x3f), not(0x1f)))

            // Copy over the return data
            returndatacopy(add(returnData, 0x20), 0, returndatasize())
        }
    }

    // Allocate a buffer to call user op validation and validation hook functions. Both of these take the form of
    // - bytes4 selector
    // - uint32 entityId
    // - PackedUserOperation userOp
    // - bytes32 userOpHash
    // The buffer starts with the selector for `preUserOpValidationHook`, and can be updated later to
    // `validateUserOp`. When perfomring the actual function calls later, update the entityId field and selector,
    // as as needed.
    function allocateUserOpValidationCallBuffer(PackedUserOperation calldata userOp, bytes32 userOpHash)
        internal
        pure
        returns (UOCallBuffer result)
    {
        bytes memory buffer =
            abi.encodeCall(IValidationHookModule.preUserOpValidationHook, (uint32(0), userOp, userOpHash));

        assembly ("memory-safe") {
            result := buffer
        }

        // Buffer contents:
        // 0xAAAAAAAA // selector
        // 0x000: 0x________________________________________________________BBBBBBBB // entityId
        // 0x020: 0x______________________________________________________________60 // userOp offset
        // 0x040: 0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // userOp hash
        // 0x060: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // userOp sender
        // 0x080: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // userOp nonce
        // 0x0a0: 0x_____________________________________________________________FFF // userOp initCode offset
        // 0x0c0: 0x_____________________________________________________________GGG // userOp callData offset
        // 0x0e0: 0xHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH // userOp accountGasLimits
        // 0x100: 0xIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII // userOp preVerificationGas
        // 0x120: 0xJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ // userOp gasFees
        // 0x140: 0x_____________________________________________________________KKK // userOp pmData offset
        // 0x160: 0x_____________________________________________________________LLL // userOp signature offset
        // 0x180...                                                                  // dynamic fields
    }

    // Converts a user op call buffer from pre user op validation hooks to user op validation.
    // Performs this by writing over the selector stored in the buffer.
    function convertToValidationBuffer(UOCallBuffer buffer) internal pure {
        // Selector is treated as a uint32 to be right-aligned in the word.
        uint32 selector = uint32(IValidationModule.validateUserOp.selector);

        assembly ("memory-safe") {
            // We want to write in the selector without writing over anything else in the buffer, so we save the
            // length, write over a portion of the length, and restore it.
            let bufferLength := mload(buffer)
            mstore(add(buffer, 4), selector)
            mstore(buffer, bufferLength)
        }
    }

    // Invokes either a user op validation hook, or validation function.
    function invokeUserOpCallBuffer(
        UOCallBuffer buffer,
        ModuleEntity moduleEntity,
        bytes calldata signatureSegment
    ) internal returns (uint256 validationData) {
        bool success;
        address moduleAddress;
        uint32 entityId;

        assembly ("memory-safe") {
            // Load the module address and entity Id
            entityId := and(shr(64, moduleEntity), 0xffffffff)
            moduleAddress := shr(96, moduleEntity)

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x24), entityId)

            // Get the offset of the user op signature in the buffer.
            // The PackedUserOperation starts at the 5th word in the buffer (0x20 * 4 = 0x80).
            // It is the 9th element in PackedUserOp (so add 0x20 * 8 = 0x100 to the buffer start).
            // So we start at 0x184, to include the selector length.
            // Then, to convert from a relative to an absolute offset, we need to add the buffer start, selector,
            // and to skip over the entityId, offset, and hash.
            let userOpSigRelativeOffset := mload(add(buffer, 0x184))
            let userOpSigAbsOffset := add(add(buffer, userOpSigRelativeOffset), 0x84)

            // Copy in the signature segment
            // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write
            // over it.
            mstore(userOpSigAbsOffset, signatureSegment.length)
            // If there is a nonzero signature segment length, copy in the data.
            if signatureSegment.length {
                // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need
                // to zero out the last word of the buffer to prevent sending garbage data.
                let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f))
                mstore(add(userOpSigAbsOffset, add(roundedDownSignatureLength, 0x20)), 0)
                calldatacopy(add(userOpSigAbsOffset, 0x20), signatureSegment.offset, signatureSegment.length)
            }

            // The data amount we actually want to call with is:
            // buffer length - word-align(oldSignature length) + word-align(newSignature length)
            // Which is equivalent to:
            // 4 (selector length) + 0x80 (entityId, user op offset, user op hash, signature length field)
            // + userOpSigRelativeOffset + word-align(newSignature length)

            let actualCallLength := add(userOpSigRelativeOffset, 0x84)

            // Add in the new signature length, with word alignment. This is safe to do because the signature
            // segment length is guaranteed to be less than the size of the previous entire signature length.
            actualCallLength := add(actualCallLength, and(add(signatureSegment.length, 0x1f), not(0x1f)))

            // Perform the call, reverting on failure or insufficient return data.

            success :=
                and(
                    // Yul evaluates expressions from right to left, so `returndatasize` will evaluate after `call`.
                    gt(returndatasize(), 0x1f),
                    call(
                        // If gas is the leftmost item before the call, it *should* be placed immediately before the
                        // call opcode and be allowed in validation.
                        gas(),
                        moduleAddress,
                        /*value*/
                        0,
                        /*argOffset*/
                        add(buffer, 0x20), // jump over 32 bytes for length
                        /*argSize*/
                        actualCallLength,
                        /*retOffset*/
                        0,
                        /*retSize*/
                        0x20
                    )
                )
        }

        if (success) {
            assembly ("memory-safe") {
                // If the call was successful, we return the first word of the return data as the validation data.
                validationData := mload(0)
            }
        } else {
            // Revert with the appropriate error type for the selector used.

            uint32 selectorUsed;
            uint32 errorSelector;

            assembly ("memory-safe") {
                selectorUsed := and(mload(add(buffer, 0x4)), 0xffffffff)
            }

            if (selectorUsed == uint32(IValidationHookModule.preUserOpValidationHook.selector)) {
                errorSelector = uint32(PreUserOpValidationHookReverted.selector);
            } else {
                errorSelector = uint32(UserOpValidationFunctionReverted.selector);
            }

            _revertModuleFunction(errorSelector, moduleAddress, entityId);
        }
    }

    function allocateRuntimeValidationCallBuffer(bytes calldata callData, bytes calldata authorization)
        internal
        returns (RTCallBuffer result)
    {
        // Allocate a call to regular runtime validation. Pre runtime validation hooks lack the `account` field, so
        // they won't touch the selector portion of this buffer.
        bytes memory buffer = abi.encodeCall(
            IValidationModule.validateRuntime,
            (address(0), uint32(0), msg.sender, msg.value, callData, authorization)
        );

        assembly ("memory-safe") {
            result := buffer
        }

        // Buffer contents, before update:
        // 0xAAAAAAAA // selector
        // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB // account
        // 0x020: 0x________________________________________________________CCCCCCCC // entityId
        // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // msg.sender
        // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // msg.value
        // 0x080: 0x______________________________________________________________c0 // callData offset
        // 0x0a0: 0x_____________________________________________________________FFF // authorization offset
        // 0x0c0...                                                                  // dynamic fields

        // Prepare the buffer for pre-runtime validation hooks.
        _prepareRuntimeCallBufferPreValidationHooks(result);
    }

    function invokeRuntimeCallBufferPreValidationHook(
        RTCallBuffer buffer,
        HookConfig hookEntity,
        bytes calldata authorizationSegment
    ) internal {
        bool success;
        address moduleAddress;
        uint32 entityId;
        assembly ("memory-safe") {
            // Load the module address and entity Id
            entityId := and(shr(64, hookEntity), 0xffffffff)
            moduleAddress := shr(96, hookEntity)

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x44), entityId)

            // Get the offset of the authorization in the buffer.
            // The authorization offset is the 6th word in the buffer (0x20 * 5 = 0xa0).
            // We need to add the buffer length and selector length (0x24) to get the start of the authorization.
            let authorizationRelativeOffset := mload(add(buffer, 0xc4))

            // Convert to an absolute offset
            // Add the lengths of the selector, buffer length field, and the authorization length field.
            let authorizationAbsOffset := add(add(buffer, authorizationRelativeOffset), 0x44)

            // Copy in the authorization segment
            // Since the buffer's copy of the authorization exceeds the length of any sub-segments, we can safely
            // write over it.
            mstore(authorizationAbsOffset, authorizationSegment.length)
            // If there is a nonzero authorization segment length, copy in the data.
            if authorizationSegment.length {
                // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need
                // to zero out the last word of the buffer to prevent sending garbage data.
                let roundedDownAuthorizationLength := and(authorizationSegment.length, not(0x1f))
                mstore(add(authorizationAbsOffset, add(roundedDownAuthorizationLength, 0x20)), 0)
                // Copy the authorization segment from calldata into the correct location in the buffer.
                calldatacopy(
                    add(authorizationAbsOffset, 0x20), authorizationSegment.offset, authorizationSegment.length
                )
            }

            // The data amount we actually want to call with is:
            // buffer length - word-align(oldAuthorization length) + word-align(newAuthorization length) - 0x20 (to
            // skip `account`),
            // This is equivalent to:
            // 4 (selector length) + 0x20 (authorization length field) + authorizationRelativeOffset +
            // word-align(newAuthorization length)

            let actualCallLength := add(authorizationRelativeOffset, 0x24)

            // Add in the new authorization length, with word alignment. This is safe to do because the
            // authorization segment length is guaranteed to be less than the size of the previous entire
            // authorization length.
            actualCallLength := add(actualCallLength, and(add(authorizationSegment.length, 0x1f), not(0x1f)))

            // Perform the call
            success :=
                call(
                    gas(),
                    moduleAddress,
                    /*value*/
                    0,
                    /*argOffset*/
                    add(buffer, 0x40), // jump over 32 bytes for length, and another 32 bytes for the account
                    /*argSize*/
                    actualCallLength,
                    /*retOffset*/
                    codesize(),
                    /*retSize*/
                    0
                )
        }

        if (!success) {
            _revertModuleFunction(uint32(PreRuntimeValidationHookReverted.selector), moduleAddress, entityId);
        }
    }

    // Note: we need to add an extra check for codesize > 0 on the module, otherwise EOAs added as runtime
    // validation would authorize all calls.
    function invokeRuntimeCallBufferValidation(
        RTCallBuffer buffer,
        ModuleEntity moduleEntity,
        bytes calldata authorizationSegment
    ) internal {
        bool success;
        address moduleAddress;
        uint32 entityId;

        assembly ("memory-safe") {
            // Load the module address and entity Id
            entityId := and(shr(64, moduleEntity), 0xffffffff)
            moduleAddress := shr(96, moduleEntity)

            // Store the account in the `account` field.
            mstore(add(buffer, 0x24), address())

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x44), entityId)

            // Fix the calldata offsets of `callData` and `authorization`, due to including the `account` field for
            // runtime validation.

            // The offset of calldata should be reset back to 0x0c0. For pre-validation hooks, it was set to 0x0a0.
            mstore(add(buffer, 0xa4), 0xc0)

            // Get the offset of the authorization in the buffer.
            // The authorization offset is the 6th word in the buffer (0x20 * 5 = 0xa0).
            let authorizationOffsetPtr := add(buffer, 0xc4)
            // Get the stored value. This will be the edited value for preRuntimeValidationHooks.
            let authorizationRelativeOffset := mload(authorizationOffsetPtr)
            // Fix the stored offset value by adding 0x20.
            authorizationRelativeOffset := add(authorizationRelativeOffset, 0x20)
            // Correct the authorization relative offset
            mstore(authorizationOffsetPtr, authorizationRelativeOffset)

            // Convert to an absolute offset
            // Add the lengths of the selector and buffer length field.
            let authorizationAbsOffset := add(add(buffer, authorizationRelativeOffset), 0x24)

            // Copy in the authorization segment
            // Since the buffer's copy of the authorization exceeds the length of any sub-segments, we can safely
            // write over it.
            mstore(authorizationAbsOffset, authorizationSegment.length)
            // If there is a nonzero authorization segment length, copy in the data.
            if authorizationSegment.length {
                // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need
                // to zero out the last word of the buffer to prevent sending garbage data.
                let roundedDownAuthorizationLength := and(authorizationSegment.length, not(0x1f))
                mstore(add(authorizationAbsOffset, add(roundedDownAuthorizationLength, 0x20)), 0)
                // Copy the authorization segment from calldata into the correct location in the buffer.
                calldatacopy(
                    add(authorizationAbsOffset, 0x20), authorizationSegment.offset, authorizationSegment.length
                )
            }

            // The data amount we actually want to call with is:
            // buffer length - word-align(oldAuthorization length) + word-align(newAuthorization length) - 0x20 (to
            // skip `account`),
            // This is equivalent to:
            // 4 (selector length) + 0x20 (authorization length field) + authorizationRelativeOffset +
            // word-align(newAuthorization length)

            let actualCallLength := add(authorizationRelativeOffset, 0x24)

            // Add in the new authorization length, with word alignment.
            // This is safe to do because the authorization segment length is guaranteed to be less than the size
            // of the previous entire authorization length.
            actualCallLength := add(actualCallLength, and(add(authorizationSegment.length, 0x1f), not(0x1f)))

            // Before performing the call, we need to check that the module has code.
            // IValidationModule.validateRuntime has no return value, so an EOA added as a validation (perhaps for
            // direct call validation) would authorize all calls, which is unsafe. Solidity inserts this check by
            // default, but when we're making calls manually via call buffers, we need to do the check ourselves.
            if iszero(extcodesize(moduleAddress)) { revert(0, 0) }

            // Perform the call
            success :=
                call(
                    gas(),
                    moduleAddress,
                    /*value*/
                    0,
                    /*argOffset*/
                    add(buffer, 0x20), // jump over 32 bytes for length
                    /*argSize*/
                    actualCallLength,
                    /*retOffset*/
                    codesize(),
                    /*retSize*/
                    0
                )
        }

        if (!success) {
            _revertModuleFunction(uint32(RuntimeValidationFunctionReverted.selector), moduleAddress, entityId);
        }
    }

    function executeRuntimeSelfCall(RTCallBuffer buffer, bytes calldata data) internal {
        bool bufferExists;

        assembly ("memory-safe") {
            bufferExists := iszero(iszero(buffer))
        }

        if (bufferExists) {
            // We don’t know whether the RTCallBuffer was called only with pre-hooks (skipping RT validation
            // updates because of SMA), or if it was called with a buffer after a module based RT validation, which
            // would cause the relative offset of calldata to change. So, when loading the callData for self-exec,
            // we must not load the relative calldata offset, and must instead use an absolute offset from the
            // start of the buffer. Using an absolute offset is safe because the abi encoder will only generate
            // “strict encoding mode” encodings, so it is guaranteed to be in that location.

            bytes memory callData;

            assembly ("memory-safe") {
                // Get the memory address of the length of callData in the buffer.
                // Because we don't know whether this will be invoked with the RTCallBuffer still as a
                callData := add(buffer, 0xe4)
            }

            // Perform the call, bubbling up revert data on failure.
            callBubbleOnRevert(address(this), msg.value, callData);
        } else {
            // No buffer exists yet, just copy the data to memory transiently and execute it.
            callBubbleOnRevertTransient(address(this), msg.value, data);
        }
    }

    // Convert a RTCallBuffer to a pre hook call buffer, if the RTCallBuffer exists. If not, allocate a new one.
    function convertToPreHookCallBuffer(RTCallBuffer buffer, bytes calldata data)
        internal
        view
        returns (PHCallBuffer result)
    {
        bool bufferExists;

        assembly ("memory-safe") {
            bufferExists := iszero(iszero(buffer))
        }

        if (bufferExists) {
            // The buffer already has most of what we need, but we need to update the pointer, length, and data
            // offset.

            // Buffer transformation:
            // 0xAAAAAAAA // selector
            // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB account -> discarded
            // 0x020: 0x________________________________________________________CCCCCCCC entityId -> selector
            // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD msg.sender -> entityId
            // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE msg.value -> sender
            // 0x080: 0x______________________________________________________________c0 callData offset -> value
            // 0x0a0: 0x_____________________________________________________________FFF auth offset -> cd offset
            // 0x0c0: 0x_____________________________________________________________GGG callData length -> stays

            // This new buffer will be a subset of the existing buffer.
            PHCallBuffer newBuffer;

            // Right-align the selector
            uint32 selector = uint32(IExecutionHookModule.preExecutionHook.selector);

            assembly ("memory-safe") {
                // We don’t know whether the RTCallBuffer was called only with pre-hooks (skipping RT validation
                // updates because of SMA), or if it was called with a buffer after a module based RT validation,
                // which would cause the relative offset of calldata to change. So, when converting to a pre hook
                // buffer, we must not load the relative calldata offset, and must instead use an absolute offset
                // from the start of the buffer. Using an absolute offset is safe because the abi encoder will only
                // generate “strict encoding mode” encodings, so it is guaranteed to be in that location.

                let callDataAbsOffset := add(buffer, 0xe4)

                let callDataSize := mload(callDataAbsOffset)

                // We must squash existing elements, because the stored offset of authorization causes the other
                // fields to not be aligned.
                // We need to copy in the selector, entityId, sender, value, and relative callData offset.

                // Step back 5 words, to start pasting in the new data.
                let workingPtr := add(buffer, 0x44)
                // Paste in the selector
                mstore(workingPtr, selector)
                // skip pasting in the entity ID, the caller will squash this later
                workingPtr := add(workingPtr, 0x40)
                // Paste in msg.sender
                mstore(workingPtr, caller())
                workingPtr := add(workingPtr, 0x20)
                // Paste in msg.value
                mstore(workingPtr, callvalue())
                workingPtr := add(workingPtr, 0x20)
                // Paste in the relative callData offset. This is now 0xa0, to show that it is after the entityId,
                // sender, value, and offset fields.
                mstore(workingPtr, 0x80)

                // Now store the buffer length. This will be directly before the selector, and the returned pointer
                // will point to this word in memory.
                newBuffer := add(buffer, 0x40)
                // word-align the callDataSize
                callDataSize := and(add(callDataSize, 0x1f), not(0x1f))
                mstore(newBuffer, add(callDataSize, 0xa4))
                // See `allocateRuntimeCallBuffer` for the buffer layout.
            }

            return newBuffer;
        } else {
            // We need to allocate and return a new buffer.
            return allocatePreExecHookCallBuffer(data);
        }
    }

    // Allocate a buffer to call a pre-execution hook.
    function allocatePreExecHookCallBuffer(bytes calldata data) internal view returns (PHCallBuffer) {
        bytes memory newBuffer =
            abi.encodeCall(IExecutionHookModule.preExecutionHook, (uint32(0), msg.sender, msg.value, data));

        PHCallBuffer result;

        assembly ("memory-safe") {
            result := newBuffer
        }

        return result;

        // Buffer contents:
        // 0xAAAAAAAA // selector
        // 0x000: 0x________________________________________________________BBBBBBBB // entityId
        // 0x020: 0x________________________CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // sender
        // 0x040: 0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // value
        // 0x060: 0x______________________________________________________________80 // callData offset
        // 0x080...                                                                  // dynamic fields
    }

    function invokePreExecHook(PHCallBuffer buffer, HookConfig hookEntity)
        internal
        returns (uint256 returnedBytesSize)
    {
        bool success;
        address moduleAddress;
        uint32 entityId;

        assembly ("memory-safe") {
            // Load the module address and entity Id
            entityId := and(shr(64, hookEntity), 0xffffffff)
            moduleAddress := shr(96, hookEntity)

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x24), entityId)

            // Perform the call, storing the first two words of return data into scratch space.
            success :=
                call(
                    gas(),
                    moduleAddress,
                    /*value*/
                    0,
                    /*argOffset*/
                    add(buffer, 0x20), // jump over 32 bytes for length
                    /*argSize*/
                    mload(buffer),
                    /*retOffset*/
                    0,
                    /*retSize*/
                    0x40
                )

            // Need at least 64 bytes of return data to be considered successful.
            success := and(success, gt(returndatasize(), 0x3f))
            // Only accept return data of "strict encoding" form, where the relative offset is exactly 0x20.
            success := and(success, eq(mload(0), 0x20))
            // Ensure that the reported length of return data does not exceed the actual length.
            // aka the stored length <= retundatasize() - 0x40 (for the first two values)
            // No opcode for lte, so the expression equals:
            // stored length < retundatasize() - 0x3f
            // Underflow doesn't matter, because success is false anyways if length < 0x40.
            returnedBytesSize := mload(0x20)
            success := and(success, lt(returnedBytesSize, sub(returndatasize(), 0x3f)))
        }

        if (!success) {
            _revertModuleFunction(uint32(PreExecHookReverted.selector), moduleAddress, entityId);
        }
    }

    // Converts a PreHookCallBuffer to a `bytes memory`, to use for a self-call in `executeUserOp`.
    // Handles skipping ahead an extra 4 bytes to omit the `executeUserOp` selector, and updates the stored length
    // to do so. This will edit the buffer.
    function getExecuteUOCallData(PHCallBuffer buffer, bytes calldata callData)
        internal
        pure
        returns (bytes memory)
    {
        bool bufferExists;

        assembly ("memory-safe") {
            bufferExists := iszero(iszero(buffer))
        }

        if (bufferExists) {
            // At this point, the buffer contains the encoded call to the pre-exec hook, but the data being sent is
            // `msg.data`, not `userOp.callData`. Re-decoding the user op struct's callData is error-prone, so
            // instead we just copy-in the provided userOp.callData, squashing the buffer. This is fine because the
            // buffer will not be reused after this operation.

            bytes memory result;

            assembly ("memory-safe") {
                // Safe to do unchecked because there must have been at least 4 bytes of callData for the
                // EntryPoint to call `executeUserOp`.
                let actualCallDataLength := sub(callData.length, 4)

                // Write over the existing buffer
                result := buffer

                // Store the new length
                mstore(result, actualCallDataLength)

                if actualCallDataLength {
                    // We don't need to write a zero word because this data will not be word-aligned before sending
                    // Copy in the callData
                    calldatacopy(add(result, 0x20), add(callData.offset, 4), actualCallDataLength)
                }
            }

            return result;
        } else {
            // No buffer exists yet, just copy the data to memory and return it.
            // Skip the first 4 bytes in this function to save the computation on the buffer reuse case.
            return callData[4:];
        }
    }

    // DensePostHookData layout
    // Very tricky to navigate, because we must do so backwards.

    // type ~= struct[] but in reverse, the caller must advance through it backwards

    // N instances of:
    // - post hook address (will be squashed with the selector later, during invocation)
    // - post hook entity Id
    // - fixed preExecHookData offset (always 0x40)
    // - preExecHookData length
    // - var-length data (right-padded with zeros to be word aligned)
    // - segment (struct) length (not counting this word, to traverse backwards)
    // 1 count of post hooks to run. The returned memory pointer will point to this value.

    function doPreHooks(HookConfig[] memory hooks, PHCallBuffer callBuffer)
        internal
        returns (DensePostHookData result)
    {
        uint256 hooksLength = hooks.length;

        // How many "post hooks to run" there are.
        uint256 resultCount;
        // Where in memory to start writing the next "post hook to run".
        bytes32 workingMemPtr;

        // Start allocating the dense buffer. From this point out, avoid any high-level memory allocations,
        // otherwise the data-in-flight may be corrupted.
        assembly ("memory-safe") {
            workingMemPtr := mload(0x40)
        }

        // Run the pre hooks and copy their return data to the dense post hooks data buffer array, if an associated
        // post exec hook exists.
        for (uint256 i = hooksLength; i > 0;) {
            // Decrement here, instead of in the loop update step, to handle the case where the length is 0.
            unchecked {
                --i;
            }

            HookConfig hookConfig = hooks[i];

            if (hookConfig.hasPreHook()) {
                uint256 returnedBytesSize = invokePreExecHook(callBuffer, hookConfig);

                // If there is an associated post exec hook, save the return data.
                if (hookConfig.hasPostHook()) {
                    // Case: both pre and post exec hook, need to save hook info, and pre hook return data

                    workingMemPtr = _appendPostHookToRun(workingMemPtr, hookConfig, returnedBytesSize);

                    ++resultCount;
                }
            } else if (hookConfig.hasPostHook()) {
                // If there is no pre hook, but there is a post hook, we still need to save a placeholder for the
                // post hook return data.

                // Case: only post exec hook, need to save hook info, and no pre hook return data
                // Call the append function with legnth 0 to put no pre hook return data.

                workingMemPtr = _appendPostHookToRun(workingMemPtr, hookConfig, 0);

                ++resultCount;
            }
        }

        // Save the length, return a pointer to the length, and update the FMP
        assembly ("memory-safe") {
            mstore(workingMemPtr, resultCount)
            result := workingMemPtr

            workingMemPtr := add(workingMemPtr, 0x20)
            mstore(0x40, workingMemPtr)
        }
    }

    function doCachedPostHooks(DensePostHookData postHookData) internal {
        uint256 postHookCount;
        uint256 workingMemPtr;

        assembly ("memory-safe") {
            postHookCount := mload(postHookData)
            workingMemPtr := sub(postHookData, 0x20)
        }

        uint32 selector = uint32(IExecutionHookModule.postExecutionHook.selector);

        // Run the post hooks.
        // This is tricky, unlike normal, we must traverse the data backwards, because the post exec hooks should
        // be executed in reverse order of the pre exec hooks.
        for (uint256 i = 0; i < postHookCount; ++i) {
            bool success;

            address moduleAddress;
            uint32 entityId;

            assembly ("memory-safe") {
                // The last word of each segment is the segment length
                let segmentLength := mload(workingMemPtr)

                // Step the working memory pointer back to the start of the segment, and preserve a copy to
                // continue the loop
                workingMemPtr := sub(workingMemPtr, segmentLength)
                let segmentStart := workingMemPtr

                // Load the post hook address
                moduleAddress := mload(workingMemPtr)
                // Load the entity id, just for the revert message
                entityId := mload(add(workingMemPtr, 0x20))

                // Squash the post hook address field with the selector
                mstore(workingMemPtr, selector)

                // Advance the working mem pointer to just before the selector, to prepare to make the call.
                workingMemPtr := add(workingMemPtr, 0x1c)

                // Compute the total call length, including the selector
                // This will be seggment length - 0x1c (28), to take out the space not used in the selector
                let callLength := sub(segmentLength, 0x1c)

                // Perform the call
                success :=
                    call(
                        gas(),
                        moduleAddress,
                        /*value*/
                        0,
                        /*argOffset*/
                        workingMemPtr,
                        /*argSize*/
                        callLength,
                        /*retOffset*/
                        codesize(),
                        /*retSize*/
                        0
                    )

                // Step the working mem pointer back to the previous segment
                workingMemPtr := sub(segmentStart, 0x20)
            }

            if (!success) {
                _revertModuleFunction(uint32(PostExecHookReverted.selector), moduleAddress, entityId);
            }
        }
    }

    function allocateSigCallBuffer(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (SigCallBuffer result)
    {
        bytes memory buffer = abi.encodeCall(
            IValidationModule.validateSignature, (address(0), uint32(0), msg.sender, hash, signature)
        );

        assembly ("memory-safe") {
            result := buffer
        }

        // Buffer contents, before update:
        // 0xAAAAAAAA // selector
        // 0x000: 0x________________________BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB // account
        // 0x020: 0x________________________________________________________CCCCCCCC // entityId
        // 0x040: 0x________________________DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD // msg.sender
        // 0x060: 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE // hash
        // 0x080: 0x______________________________________________________________a0 // signature offset
        // 0x0a0...                                                                  // dynamic fields

        // Prepare the buffer for pre-signature validation hooks.
        _prepareSigValidationCallBufferPreSigValidationHooks(result);
    }

    function invokePreSignatureValidationHook(
        SigCallBuffer buffer,
        HookConfig hookEntity,
        bytes calldata signatureSegment
    ) internal view {
        bool success;
        address moduleAddress;
        uint32 entityId;

        assembly ("memory-safe") {
            // Load the module address and entity id
            entityId := and(shr(64, hookEntity), 0xffffffff)
            moduleAddress := shr(96, hookEntity)

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x44), entityId)

            // Copy in the signature segment
            // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write
            // over it.
            mstore(add(buffer, 0xc4), signatureSegment.length)

            // If there is a nonzero signature segment length, copy in the data.
            if signatureSegment.length {
                // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need
                // to zero out the last word of the buffer to prevent sending garbage data.
                let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f))
                mstore(add(add(buffer, 0xe4), roundedDownSignatureLength), 0)
                // Copy in the data
                calldatacopy(add(buffer, 0xe4), signatureSegment.offset, signatureSegment.length)
            }

            // The data amount we actually want to call with is:
            // 0xa4 (4 byte selector + 5 words of data: entity id, sender, hash, signature offset, signature
            // length) + word-align(signature length)
            let actualCallLength := add(0xa4, and(add(signatureSegment.length, 0x1f), not(0x1f)))

            // Perform the call
            success :=
                staticcall(
                    gas(),
                    moduleAddress,
                    /*argOffset*/
                    add(buffer, 0x40), // jump over 32 bytes for length, and another 32 bytes for the account
                    /*argSize*/
                    actualCallLength,
                    /*retOffset*/
                    0,
                    /*retSize*/
                    0x20
                )
        }

        if (!success) {
            _revertModuleFunction(uint32(PreSignatureValidationHookReverted.selector), moduleAddress, entityId);
        }
    }

    function invokeSignatureValidation(
        SigCallBuffer buffer,
        ModuleEntity validationFunction,
        bytes calldata signatureSegment
    ) internal view returns (bytes4 result) {
        bool success;
        address moduleAddress;
        uint32 entityId;

        assembly ("memory-safe") {
            // Load the module address and entity id
            entityId := and(shr(64, validationFunction), 0xffffffff)
            moduleAddress := shr(96, validationFunction)

            // Store the account in the `account` field.
            mstore(add(buffer, 0x24), address())

            // Update the buffer with the entity Id
            mstore(add(buffer, 0x44), entityId)

            // Fix the calldata offsets of `signature`, due to including the `account` field for signature
            // validation.
            mstore(add(buffer, 0xa4), 0xa0)

            // Copy in the signature segment
            // Since the buffer's copy of the signature exceeds the length of any sub-segments, we can safely write
            // over it.
            mstore(add(buffer, 0xc4), signatureSegment.length)

            // If there is a nonzero signature segment length, copy in the data.
            if signatureSegment.length {
                // Because we will be sending the data with word-aligned padding ("strict ABI encoding"), we need
                // to zero out the last word of the buffer to prevent sending garbage data.
                let roundedDownSignatureLength := and(signatureSegment.length, not(0x1f))
                mstore(add(add(buffer, 0xe4), roundedDownSignatureLength), 0)
                // Copy in the data
                calldatacopy(add(buffer, 0xe4), signatureSegment.offset, signatureSegment.length)
            }

            // The data amount we actually want to call with is:
            // 0xc4 (4 byte selector + 6 words of data: account, entity id, sender, hash, signature offset,
            // signature length) + word-align(signature length)
            let actualCallLength := add(0xc4, and(add(signatureSegment.length, 0x1f), not(0x1f)))

            // Perform the call
            success :=
                and(
                    // Yul evaluates expressions from right to left, so `returndatasize` will evaluate after
                    // `staticcall`.
                    gt(returndatasize(), 0x1f),
                    staticcall(
                        gas(),
                        moduleAddress,
                        /*argOffset*/
                        add(buffer, 0x20), // jump over 32 bytes for length, and another 32 bytes for the account
                        /*argSize*/
                        actualCallLength,
                        /*retOffset*/
                        0,
                        /*retSize*/
                        0x20
                    )
                )
        }

        if (success) {
            assembly ("memory-safe") {
                // Otherwise, we return the first word of the return data as the signature validation result
                result := mload(0)

                // If any of the lower 28 bytes are nonzero, it would be an abi decoding failure.
                if shl(32, result) { revert(0, 0) }
            }
        } else {
            _revertModuleFunction(uint32(SignatureValidationFunctionReverted.selector), moduleAddress, entityId);
        }
    }

    /// @notice Appends a post hook to run to the dense post hook data buffer.
    /// @param workingMemPtr The current working memory pointer
    /// @param hookConfig The hook configuration
    /// @param returnedBytesSize The size of the returned bytes from the pre hook
    /// @return The new working memory pointer
    function _appendPostHookToRun(bytes32 workingMemPtr, HookConfig hookConfig, uint256 returnedBytesSize)
        private
        pure
        returns (bytes32)
    {
        // Each segment starts out at a length of 4 words:
        // - post hook address
        // - post hook entity Id
        // - fixed preExecHookData offset (always 0x40)
        // - preHookReturnData length
        // Add to this the word-aligned length of the pre hook return data.
        uint256 segmentLength = 0x80;

        assembly ("memory-safe") {
            // Load the module address and entity Id
            let entityId := and(shr(64, hookConfig), 0xffffffff)
            let moduleAddress := shr(96, hookConfig)

            // Get the word-aligned data to copy length
            let alignedDataLength := and(add(returnedBytesSize, 0x1f), not(0x1f))

            segmentLength := add(segmentLength, alignedDataLength)

            // Start writing to memory:

            // Store the post hook address
            mstore(workingMemPtr, moduleAddress)
            workingMemPtr := add(workingMemPtr, 0x20)

            // Store the post hook entity Id
            mstore(workingMemPtr, entityId)
            workingMemPtr := add(workingMemPtr, 0x20)

            // Store the fixed preExecHookData offset
            mstore(workingMemPtr, 0x40)
            workingMemPtr := add(workingMemPtr, 0x20)

            // Store the preHookReturnData length
            mstore(workingMemPtr, returnedBytesSize)
            workingMemPtr := add(workingMemPtr, 0x20)

            // Copy in the pre hook return data, if any exists
            if returnedBytesSize {
                // Zero out the last memory word to encode in strict ABI mode
                let roundedDownDataLength := and(returnedBytesSize, not(0x1f))
                mstore(add(workingMemPtr, roundedDownDataLength), 0)

                // Copy in the data
                returndatacopy(workingMemPtr, 0x40, returnedBytesSize)
                workingMemPtr := add(workingMemPtr, alignedDataLength)
            }

            // Store the overall segment length at the end
            mstore(workingMemPtr, segmentLength)
            workingMemPtr := add(workingMemPtr, 0x20)
        }

        return workingMemPtr;
    }

    function _revertModuleFunction(uint32 errorSelector, address moduleAddress, uint32 entityId) private pure {
        // All of the module function reverts have the same parameter layout:
        // - module address
        // - entity Id
        // - revert data

        assembly ("memory-safe") {
            let m := mload(0x40)
            // Write in order of entityId -> address -> selector, to avoid masking or shifts.
            mstore(add(m, 0x18), entityId)
            mstore(add(m, 0x14), moduleAddress)
            mstore(m, errorSelector)
            mstore(add(m, 0x40), 0x40) // fixed offset for the revert data
            mstore(add(m, 0x60), returndatasize())

            if returndatasize() {
                // Store a zero in the last word of the revert data, to do strict ABI-encoding for the error.
                let roundedDownDataLength := and(returndatasize(), not(0x1f))
                mstore(add(m, add(0x80, roundedDownDataLength)), 0)
                returndatacopy(add(m, 0x80), 0, returndatasize())
            }

            let roundedUpDataLength := and(add(returndatasize(), 0x1f), not(0x1f))

            // 4 bytes for the selector, and 0x60 for the 3 words of fixed-size data.
            let totalRevertDataLength := add(0x64, roundedUpDataLength)

            revert(add(m, 0x1c), totalRevertDataLength)
        }
    }

    function _prepareRuntimeCallBufferPreValidationHooks(RTCallBuffer buffer) private pure {
        uint32 selector = uint32(IValidationHookModule.preRuntimeValidationHook.selector);
        assembly ("memory-safe") {
            // Update the buffer with the selector. This will squash a portion of the `account` param for runtime
            // validation, but that will be restored before calling.
            mstore(add(buffer, 0x24), selector)

            // Fix the calldata offsets of `callData` and `authorization`, due to excluding the `account` field.

            // The offset of calldata starts out as 0x0c0, but for pre-validation hooks, it should be 0x0a0.
            mstore(add(buffer, 0xa4), 0xa0)

            // The offset of authorization should be decremented by one word.
            let authorizationOffsetPtr := add(buffer, 0xc4)
            // Get the stored value. This will be wrong for preRuntimeValidationHooks, because the buffer size is
            // smaller by 1 word.
            let authorizationOffset := mload(authorizationOffsetPtr)
            // Fix the stored offset value
            mstore(authorizationOffsetPtr, sub(authorizationOffset, 0x20))
        }
    }

    function _prepareSigValidationCallBufferPreSigValidationHooks(SigCallBuffer buffer) private pure {
        uint32 selector = uint32(IValidationHookModule.preSignatureValidationHook.selector);
        assembly ("memory-safe") {
            // Update the buffer with the selector. This will squash a portion of the `account` param for signature
            // validation, but that will be restored before calling.
            mstore(add(buffer, 0x24), selector)

            // Fix the calldata offset of `signature`, due to excluding the `account` field.

            // The offset of the signature starts out as 0xa0, but for pre-validation hooks, it should be 0x80.
            mstore(add(buffer, 0xa4), 0x80)
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {HookConfig} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";

import {ExecutionStorage, ValidationStorage} from "../account/AccountStorage.sol";
import {LinkedListSet, LinkedListSetLib, SENTINEL_VALUE, SetValue} from "./LinkedListSetLib.sol";

type MemSnapshot is uint256;

/// @title Memory Management Library
/// @author Alchemy
/// @notice A library for managing memory in ModularAccount. Handles loading data from storage into memory, and
/// manipulating the free memory pointer.
library MemManagementLib {
    /// @notice Load execution hooks associated both with a validation function and an execution selector.
    /// @param execData The execution storage struct to load from.
    /// @param valData The validation storage struct to load from.
    /// @return hooks An array of `HookConfig` items, representing the execution hooks.
    function loadExecHooks(ExecutionStorage storage execData, ValidationStorage storage valData)
        internal
        view
        returns (HookConfig[] memory hooks)
    {
        // Load selector-assoc hooks first, then validation-assoc, because execution order is reversed
        // This next code segment is adapted from the function LinkedListSetLib.getAll.
        mapping(bytes32 => bytes32) storage llsMap = execData.executionHooks.map;
        uint256 size = 0;
        bytes32 cursor = llsMap[SENTINEL_VALUE];

        // Dynamically allocate the returned array as we iterate through the set, since we don't know the size
        // beforehand.
        // This is accomplished by first writing to memory after the free memory pointer,
        // then updating the free memory pointer to cover the newly-allocated data.
        // To the compiler, writes to memory after the free memory pointer are considered "memory safe".
        // See https://docs.soliditylang.org/en/v0.8.22/assembly.html#memory-safety
        // Stack variable lifting done when compiling with via-ir will only ever place variables into memory
        // locations below the current free memory pointer, so it is safe to compile this library with via-ir.
        // See https://docs.soliditylang.org/en/v0.8.22/yul.html#memoryguard
        assembly ("memory-safe") {
            // It is critical that no other memory allocations occur between:
            // -  loading the value of the free memory pointer into `ret`
            // -  updating the free memory pointer to point to the newly-allocated data, which is done after all
            // the values have been written.
            hooks := mload(0x40)
        }

        while (!LinkedListSetLib.isSentinel(cursor) && cursor != bytes32(0)) {
            unchecked {
                ++size;
            }
            // Place the item into the return array manually. Since the size was just incremented, it will point to
            // the next location to write to.
            assembly ("memory-safe") {
                mstore(add(hooks, mul(size, 0x20)), cursor)
            }

            cursor = llsMap[cursor];
        }

        // Load validation-assoc hooks
        uint256 validationAssocHooksLength = valData.executionHookCount;
        llsMap = valData.executionHooks.map;
        // Notably, we invert the mapping lookup ordering for validation-assoc hooks, because we know the length
        // ahead-of-time, thus saving an `sload`. This is why the cursor starts at SENTINEL_VALUE.
        cursor = SENTINEL_VALUE;

        for (uint256 i = 0; i < validationAssocHooksLength; ++i) {
            unchecked {
                ++size;
            }

            cursor = llsMap[cursor];

            assembly ("memory-safe") {
                mstore(add(hooks, mul(size, 0x20)), cursor)
            }
        }

        assembly ("memory-safe") {
            // Update the free memory pointer with the now-known length of the array.
            mstore(0x40, add(hooks, mul(add(size, 1), 0x20)))
            // Set the length of the array.
            mstore(hooks, size)
        }

        return hooks;
    }

    /// @notice Load execution hooks associated with an execution selector.
    /// @param execData The execution storage struct to load from.
    /// @return hooks An array of `HookConfig` items, representing the execution hooks.
    function loadExecHooks(ExecutionStorage storage execData) internal view returns (HookConfig[] memory) {
        HookConfig[] memory hooks;

        SetValue[] memory hooksSet = LinkedListSetLib.getAll(execData.executionHooks);

        // SetValue is internally a bytes31, and HookConfig is a bytes25, which are both left-aligned. This cast is
        // safe so long as only HookConfig entries are added to the set.
        assembly ("memory-safe") {
            hooks := hooksSet
        }

        return hooks;
    }

    /// @notice Load execution hooks associated with a validation function.
    /// @param valData The validation storage struct to load from.
    /// @return hooks An array of `HookConfig` items, representing the execution hooks.
    function loadExecHooks(ValidationStorage storage valData) internal view returns (HookConfig[] memory) {
        uint256 validationAssocHooksLength = valData.executionHookCount;

        return _loadValidationAssociatedHooks(validationAssocHooksLength, valData.executionHooks);
    }

    /// @notice Load validation hooks associated with a validation function.
    /// @param valData The validation storage struct to load from.
    /// @return hooks An array of `HookConfig` items, representing the validation hooks.
    function loadValidationHooks(ValidationStorage storage valData) internal view returns (HookConfig[] memory) {
        uint256 validationHookCount = valData.validationHookCount;

        return _loadValidationAssociatedHooks(validationHookCount, valData.validationHooks);
    }

    /// @notice Load all selectors that have been added to a validation function.
    /// @param valData The validation storage struct to load from.
    /// @return selectors An array of the selectors the validation function is allowed to validate.
    function loadSelectors(ValidationStorage storage valData) internal view returns (bytes4[] memory selectors) {
        SetValue[] memory selectorsSet = LinkedListSetLib.getAll(valData.selectors);

        // SetValue is internally a bytes31, and both bytes4 and bytes31 are left-aligned. This cast is safe so
        // long as only bytes4 entries are added to the set.
        assembly ("memory-safe") {
            selectors := selectorsSet
        }

        return selectors;
    }

    /// @notice Reverses an array of `HookConfig` items in place.
    function reverseArr(HookConfig[] memory hooks) internal pure {
        bytes32[] memory casted;

        // Cast to bytes32[] to use the shared reverseArr function
        assembly ("memory-safe") {
            casted := hooks
        }

        _reverseArr(casted);
    }

    /// @notice Reverses an array of `bytes4` items in place.
    function reverseArr(bytes4[] memory selectors) internal pure {
        bytes32[] memory casted;

        // Cast to bytes32[] to use the shared reverseArr function
        assembly ("memory-safe") {
            casted := selectors
        }

        _reverseArr(casted);
    }

    /// @notice If the callData is an encoded function call to IModularAccount.execute, retrieves the target of the
    /// call.
    /// @param callData The calldata to check.
    /// @return target The target of the call.
    function getExecuteTarget(bytes calldata callData) internal pure returns (address) {
        address target;

        assembly ("memory-safe") {
            target := and(calldataload(add(callData.offset, 4)), 0xffffffffffffffffffffffffffffffffffffffff)
        }

        return target;
    }

    /// @notice Captures a snapshot of the free memory pointer.
    /// @return The snapshot of the free memory pointer.
    function freezeFMP() internal pure returns (MemSnapshot) {
        MemSnapshot snapshot;

        assembly ("memory-safe") {
            snapshot := mload(0x40)
        }

        return snapshot;
    }

    /// @notice Restores the free memory pointer to a previous snapshot.
    /// @dev This invalidates any memory allocated since the snapshot was taken.
    /// @param snapshot The snapshot to restore to.
    function restoreFMP(MemSnapshot snapshot) internal pure {
        assembly ("memory-safe") {
            mstore(0x40, snapshot)
        }
    }

    /// @notice Used to load both pre validation hooks and pre execution hooks, associated with a validation
    /// function. The caller must first get the length of the hooks from the ValidationStorage struct.
    function _loadValidationAssociatedHooks(uint256 hookCount, LinkedListSet storage hooks)
        private
        view
        returns (HookConfig[] memory)
    {
        HookConfig[] memory hookArr = new HookConfig[](hookCount);

        mapping(bytes32 => bytes32) storage llsMap = hooks.map;
        bytes32 cursor = SENTINEL_VALUE;

        for (uint256 i = 0; i < hookCount; ++i) {
            cursor = llsMap[cursor];
            hookArr[i] = HookConfig.wrap(bytes25(cursor));
        }

        return hookArr;
    }

    function _reverseArr(bytes32[] memory hooks) private pure {
        uint256 len = hooks.length;
        uint256 halfLen = len / 2;

        for (uint256 i = 0; i < halfLen; ++i) {
            uint256 j = len - i - 1;

            (hooks[i], hooks[j]) = (hooks[j], hooks[i]);
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {DIRECT_CALL_VALIDATION_ENTITY_ID} from "@erc6900/reference-implementation/helpers/Constants.sol";
import {ModuleEntity, ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol";
import {
    ValidationConfig,
    ValidationConfigLib
} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol";

import {ValidationStorage} from "../account/AccountStorage.sol";

// A type representing a validation lookup key and flags for validation options.
// The validation lookup key is a tagged union between a direct call validation address and a validation entity ID.
type ValidationLocator is uint168;
// Layout:
// Unused
// 0x0000000000000000000000__________________________________________
// Either the direct call validation's address, or the entity ID for non-direct-call validation.
// 0x______________________AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__
// Validation options
// 0x______________________________________________________________BB

// ValidationOptions layout:
// 0b00000___ // Unused
// 0b_____A__ // is direct call validation (union tag)
// 0b______B_ // has deferred action
// 0b_______C // is global validation

// A type representing only the validation lookup key, with validation options masked out except for the
// direct call validation flag.
type ValidationLookupKey is uint168;

using ValidationLocatorLib for ValidationLocator global;
using ValidationLocatorLib for ValidationLookupKey global;

library ValidationLocatorLib {
    using ValidationConfigLib for ValidationConfig;

    uint8 internal constant _VALIDATION_TYPE_GLOBAL = 1;
    uint8 internal constant _HAS_DEFERRED_ACTION = 2;
    uint8 internal constant _IS_DIRECT_CALL_VALIDATION = 4;

    function moduleEntity(ValidationLookupKey _lookupKey, ValidationStorage storage validationStorage)
        internal
        view
        returns (ModuleEntity result)
    {
        if (_lookupKey.isDirectCallValidation()) {
            result = ModuleEntityLib.pack(_lookupKey.directCallAddress(), DIRECT_CALL_VALIDATION_ENTITY_ID);
        } else {
            result = ModuleEntityLib.pack(validationStorage.module, _lookupKey.entityId());
        }
    }

    // User op nonce, 4337 mandated layout:
    // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________ // Parallel Nonce Key
    // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key

    // User op nonce, Alchemy MA usage:
    // With non-direct call validation
    // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__________________________ // Parallel Nonce Key
    // 0x______________________________________BBBBBBBB__________________ // Validation Entity ID
    // 0x______________________________________________CC________________ // Options byte
    // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key

    // With direct call validation
    // 0xAAAAAA__________________________________________________________ // Parallel Nonce Key
    // 0x______BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB__________________ // Caller address of direct-call
    // validation
    // 0x______________________________________________CC________________ // Options byte
    // 0x________________________________________________BBBBBBBBBBBBBBBB // Sequential Nonce Key
    function loadFromNonce(uint256 nonce) internal pure returns (ValidationLocator result) {
        assembly ("memory-safe") {
            nonce := shr(64, nonce)
            let validationType := and(nonce, _IS_DIRECT_CALL_VALIDATION)

            switch validationType
            case 0 {
                // If not using direct call validation, the validation locator contains a 4-byte entity ID
                // Mask it to the lower 5 bytes
                result := and(nonce, 0xFFFFFFFFFF)
            }
            default {
                // If using direct call validation, the validation locator contains a 20-byte address
                // Mask it to the lower 21 bytes
                result := and(nonce, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
            }
        }
    }

    // executeRuntimeValidation authorization layout, and isValidSignature signature layout
    // [1-byte options][4-byte validation id OR 20-byte address of direct call validation][remainder]

    // With non-direct call validation
    // 0xAA______________ // Validation Type
    // 0x__BBBBBBBB______ // Validation Entity ID
    // 0x__________CCC... // Remainder

    // With direct call validation
    // 0xAA______________________________________________ // Validation Type
    // 0x__BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB______ // Caller address of direct-call validation
    // 0x__________________________________________CCC... // Remainder
    function loadFromSignature(bytes calldata signature)
        internal
        pure
        returns (ValidationLocator result, bytes calldata remainder)
    {
        assembly ("memory-safe") {
            // Regular validation requires at least 5 bytes. Direct call validation requires at least 21 bytes,
            // checked later.
            if lt(signature.length, 5) { revert(0, 0) }

            result := calldataload(signature.offset)

            let validationOptions := shr(248, result)

            switch and(validationOptions, _IS_DIRECT_CALL_VALIDATION)
            case 0 {
                // If not using direct call validation, the validation locator contains a 32-byte entity ID

                // Result contains:
                // 0xAA______________________________________________________________ // Validation Type
                // 0x__BBBBBBBB______________________________________________________ // Validation Entity ID
                // 0x__________CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Remainder bits and/or
                // zeros

                // We need to clear the upper byte by shifting left 1 bytes (8 bits), then shift right 28 bytes
                // (224 bits), leaving only the entity ID.
                result := shr(224, shl(8, result))
                // Next, we need to set the validation type, which is 0 in this branch
                result := or(shl(8, result), validationOptions)

                // Advance the remainder by 5 bytes
                remainder.offset := add(signature.offset, 5)
                remainder.length := sub(signature.length, 5)
            }
            default {
                // Direct call validation requires at least 21 bytes
                if lt(signature.length, 21) { revert(0, 0) }

                // If using direct call validation, the validation locator contains a 20-byte address
                // Result contains:
                // 0xAA______________________________________________________________ // Validation Type
                // 0x__BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB______________________ // Caller address of
                // direct-call validation
                // 0x__________________________________________CCCCCCCCCCCCCCCCCCCCCC // Remainder bits and/or
                // zeros

                // So we need to clear the upper byte by shifting left 1 bytes (8 bits), then shift right 12
                // bytes (96 bits) to get the address.
                result := shr(96, shl(8, result))
                // Next, we need to set the validation type
                result := or(shl(8, result), validationOptions)

                // Advance the remainder by 21 bytes
                remainder.offset := add(signature.offset, 21)
                remainder.length := sub(signature.length, 21)
            }
        }
    }

    // Only safe to call if the lookup has been asserted to be a direct call validation.
    function directCallAddress(ValidationLookupKey _lookupKey) internal pure returns (address result) {
        assembly ("memory-safe") {
            result := and(shr(8, _lookupKey), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        }
    }

    // Only safe to call if the lookup has been asserted to be a non-direct call validation.
    function entityId(ValidationLookupKey _lookupKey) internal pure returns (uint32 result) {
        assembly ("memory-safe") {
            result := and(shr(8, _lookupKey), 0xFFFFFFFF)
        }
    }

    function isGlobal(ValidationLocator locator) internal pure returns (bool) {
        return (ValidationLocator.unwrap(locator) & _VALIDATION_TYPE_GLOBAL) != 0;
    }

    function hasDeferredAction(ValidationLocator locator) internal pure returns (bool) {
        return (ValidationLocator.unwrap(locator) & _HAS_DEFERRED_ACTION) != 0;
    }

    function isDirectCallValidation(ValidationLookupKey _lookupKey) internal pure returns (bool) {
        return (ValidationLookupKey.unwrap(_lookupKey) & _IS_DIRECT_CALL_VALIDATION) != 0;
    }

    function configToLookupKey(ValidationConfig validationConfig)
        internal
        pure
        returns (ValidationLookupKey result)
    {
        if (validationConfig.entityId() == DIRECT_CALL_VALIDATION_ENTITY_ID) {
            result = ValidationLookupKey.wrap(
                uint168(uint160(validationConfig.module())) << 8 | _IS_DIRECT_CALL_VALIDATION
            );
        } else {
            result = ValidationLookupKey.wrap(uint168(uint160(validationConfig.entityId())) << 8);
        }
    }

    function moduleEntityToLookupKey(ModuleEntity _moduleEntity)
        internal
        pure
        returns (ValidationLookupKey result)
    {
        (address module, uint32 _entityId) = ModuleEntityLib.unpack(_moduleEntity);
        if (_entityId == DIRECT_CALL_VALIDATION_ENTITY_ID) {
            result = ValidationLookupKey.wrap(uint168(uint160(module)) << 8 | _IS_DIRECT_CALL_VALIDATION);
        } else {
            result = ValidationLookupKey.wrap(uint168(uint160(_entityId)) << 8);
        }
    }

    function directCallLookupKey(address directCallValidation)
        internal
        pure
        returns (ValidationLookupKey result)
    {
        result = ValidationLookupKey.wrap(uint168(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION);
    }

    function lookupKey(ValidationLocator locator) internal pure returns (ValidationLookupKey result) {
        assembly ("memory-safe") {
            result := and(locator, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04)
        }
    }

    // Packing functions. These should not be used in the account, but in scripts and tests.

    function pack(uint32 _entityId, bool _isGlobal, bool _hasDeferredAction)
        internal
        pure
        returns (ValidationLocator)
    {
        uint168 result = uint168(_entityId) << 8;
        if (_isGlobal) {
            result |= _VALIDATION_TYPE_GLOBAL;
        }
        if (_hasDeferredAction) {
            result |= _HAS_DEFERRED_ACTION;
        }

        return ValidationLocator.wrap(result);
    }

    function packDirectCall(address directCallValidation, bool _isGlobal, bool _hasDeferredAction)
        internal
        pure
        returns (ValidationLocator)
    {
        uint168 result = uint168(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION;
        if (_isGlobal) {
            result |= _VALIDATION_TYPE_GLOBAL;
        }
        if (_hasDeferredAction) {
            result |= _HAS_DEFERRED_ACTION;
        }

        return ValidationLocator.wrap(result);
    }

    function packNonce(uint32 validationEntityId, bool _isGlobal, bool _hasDeferredAction)
        internal
        pure
        returns (uint256 result)
    {
        result = uint256(validationEntityId) << 8;
        if (_isGlobal) {
            result |= _VALIDATION_TYPE_GLOBAL;
        }
        if (_hasDeferredAction) {
            result |= _HAS_DEFERRED_ACTION;
        }
        // Finally, shift left to make space for the sequential nonce key
        result <<= 64;
    }

    function packNonceDirectCall(address directCallValidation, bool _isGlobal, bool _hasDeferredAction)
        internal
        pure
        returns (uint256 result)
    {
        result = uint256(uint160(directCallValidation)) << 8 | _IS_DIRECT_CALL_VALIDATION;
        if (_isGlobal) {
            result |= _VALIDATION_TYPE_GLOBAL;
        }
        if (_hasDeferredAction) {
            result |= _HAS_DEFERRED_ACTION;
        }
        // Finally, shift left to make space for the sequential nonce key
        result <<= 64;
    }

    function packSignature(uint32 validationEntityId, bool _isGlobal, bytes memory signature)
        internal
        pure
        returns (bytes memory result)
    {
        uint8 options = 0;
        if (_isGlobal) {
            options |= _VALIDATION_TYPE_GLOBAL;
        }

        return bytes.concat(abi.encodePacked(options, uint32(validationEntityId)), signature);
    }

    function packSignatureDirectCall(
        address directCallValidation,
        bool _isGlobal,
        bool _hasDeferredAction,
        bytes memory signature
    ) internal pure returns (bytes memory result) {
        uint8 options = _IS_DIRECT_CALL_VALIDATION;
        if (_isGlobal) {
            options |= _VALIDATION_TYPE_GLOBAL;
        }
        if (_hasDeferredAction) {
            options |= _HAS_DEFERRED_ACTION;
        }

        return bytes.concat(abi.encodePacked(options, uint160(directCallValidation)), signature);
    }

    // Converts a module entity to a locator.
    function packFromModuleEntity(ModuleEntity _moduleEntity, bool _isGlobal, bool _hasDeferredAction)
        internal
        pure
        returns (ValidationLocator)
    {
        uint168 result;

        (address module, uint32 _entityId) = ModuleEntityLib.unpack(_moduleEntity);
        if (_entityId == DIRECT_CALL_VALIDATION_ENTITY_ID) {
            result = uint168(uint160(module)) << 8 | _IS_DIRECT_CALL_VALIDATION;
        } else {
            result = uint168(_entityId) << 8;
        }

        if (_isGlobal) {
            result |= _VALIDATION_TYPE_GLOBAL;
        }

        if (_hasDeferredAction) {
            result |= _HAS_DEFERRED_ACTION;
        }

        return ValidationLocator.wrap(result);
    }

    // Operators

    function eq(ValidationLookupKey a, ValidationLookupKey b) internal pure returns (bool) {
        return ValidationLookupKey.unwrap(a) == ValidationLookupKey.unwrap(b);
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

/// @title Account Base
/// @author Alchemy
/// @dev An optimized implementation of a base account contract for ERC-4337.
/// Provides a public view function for getting the EntryPoint address, but does not provide one for getting the
/// nonce. The nonce may be retrieved from the EntryPoint contract.
/// Implementing contracts should override the _validateUserOp function to provide account-specific validation
/// logic.
abstract contract AccountBase is IAccount {
    IEntryPoint internal immutable _ENTRY_POINT;

    error NotEntryPoint();

    constructor(IEntryPoint _entryPoint) {
        _ENTRY_POINT = _entryPoint;
    }

    /// @inheritdoc IAccount
    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
        external
        override
        returns (uint256 validationData)
    {
        _requireFromEntryPoint();

        validationData = _validateUserOp(userOp, userOpHash);

        // Pay the prefund if necessary.
        assembly ("memory-safe") {
            if missingAccountFunds {
                // Ignore failure (it's EntryPoint's job to verify, not the account's).
                pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00))
            }
        }
    }

    /// @notice Gets the entry point for this account
    /// @return entryPoint The entry point for this account
    function entryPoint() external view returns (IEntryPoint) {
        return _ENTRY_POINT;
    }

    /// @notice Account-specific implementation of user op validation. Override this function to define the
    /// account's validation logic.
    function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
        internal
        virtual
        returns (uint256 validationData);

    /// @notice Revert if the sender is not the EntryPoint.
    function _requireFromEntryPoint() internal view {
        if (msg.sender != address(_ENTRY_POINT)) {
            revert NotEntryPoint();
        }
    }
}

File 45 of 70 : AccountStorageInitializable.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {AccountStorage, getAccountStorage} from "./AccountStorage.sol";

/// @title Account Storage Initializable
/// @author Alchemy
/// @notice A contract mixin that provides the functionality of OpenZeppelin's Initializable contract, using the
/// custom storage layout defined by the AccountStorage struct.
/// @dev The implementation logic here is modified from OpenZeppelin's Initializable contract from v5.0.
abstract contract AccountStorageInitializable {
    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /// @notice Modifier to put on function intended to be called only once per implementation
    /// @dev Reverts if the contract has already been initialized
    modifier initializer() {
        AccountStorage storage $ = getAccountStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$.initializing;
        uint64 initialized = $.initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $.initialized = 1;
        if (isTopLevelCall) {
            $.initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $.initializing = false;
            emit Initialized(1);
        }
    }

    /// @notice Internal function to disable calls to initialization functions
    /// @dev Reverts if the contract is currently initializing.
    function _disableInitializers() internal virtual {
        AccountStorage storage $ = getAccountStorage();
        if ($.initializing) {
            revert InvalidInitialization();
        }
        if ($.initialized != type(uint8).max) {
            $.initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {
    HookConfig,
    IModularAccount,
    ModuleEntity
} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {
    ExecutionDataView,
    IModularAccountView,
    ValidationDataView
} from "@erc6900/reference-implementation/interfaces/IModularAccountView.sol";
import {IAccountExecute} from "@eth-infinitism/account-abstraction/interfaces/IAccountExecute.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IModularAccountBase} from "../interfaces/IModularAccountBase.sol";
import {MemManagementLib} from "../libraries/MemManagementLib.sol";
import {ValidationLocatorLib} from "../libraries/ValidationLocatorLib.sol";
import {AccountBase} from "./AccountBase.sol";
import {ExecutionStorage, ValidationStorage, getAccountStorage} from "./AccountStorage.sol";

/// @title Modular Account View
/// @author Alchemy
/// @notice This abstract contract implements the two view functions to get validation and execution data for an
/// account.
abstract contract ModularAccountView is IModularAccountView {
    /// @inheritdoc IModularAccountView
    function getExecutionData(bytes4 selector) external view override returns (ExecutionDataView memory data) {
        ExecutionStorage storage executionStorage = getAccountStorage().executionStorage[selector];

        if (_isNativeFunction(uint32(selector))) {
            bool isGlobalValidationAllowed = _isGlobalValidationAllowedNativeFunction(uint32(selector));
            data.module = address(this);
            data.skipRuntimeValidation = !isGlobalValidationAllowed;
            data.allowGlobalValidation = isGlobalValidationAllowed;
            if (!_isWrappedNativeFunction(uint32(selector))) {
                // The native function does not run execution hooks associated with its selector, so
                // we can return early.
                return data;
            }
        } else {
            data.module = executionStorage.module;
            data.skipRuntimeValidation = executionStorage.skipRuntimeValidation;
            data.allowGlobalValidation = executionStorage.allowGlobalValidation;
        }

        HookConfig[] memory hooks = MemManagementLib.loadExecHooks(executionStorage);
        MemManagementLib.reverseArr(hooks);
        data.executionHooks = hooks;
    }

    /// @inheritdoc IModularAccountView
    function getValidationData(ModuleEntity validationFunction)
        external
        view
        override
        returns (ValidationDataView memory data)
    {
        ValidationStorage storage validationStorage =
            getAccountStorage().validationStorage[ValidationLocatorLib.moduleEntityToLookupKey(validationFunction)];
        data.validationFlags = validationStorage.validationFlags;
        data.validationHooks = MemManagementLib.loadValidationHooks(validationStorage);
        MemManagementLib.reverseArr(data.validationHooks);

        HookConfig[] memory hooks = MemManagementLib.loadExecHooks(validationStorage);
        MemManagementLib.reverseArr(hooks);
        data.executionHooks = hooks;

        bytes4[] memory selectors = MemManagementLib.loadSelectors(validationStorage);
        MemManagementLib.reverseArr(selectors);
        data.selectors = selectors;
    }

    function _isNativeFunction(uint32 selector) internal pure virtual returns (bool) {
        return (
            _isGlobalValidationAllowedNativeFunction(selector)
                || selector == uint32(AccountBase.entryPoint.selector)
                || selector == uint32(AccountBase.validateUserOp.selector)
                || selector == uint32(IERC1155Receiver.onERC1155BatchReceived.selector)
                || selector == uint32(IERC1155Receiver.onERC1155Received.selector)
                || selector == uint32(IERC1271.isValidSignature.selector)
                || selector == uint32(IERC165.supportsInterface.selector)
                || selector == uint32(IERC721Receiver.onERC721Received.selector)
                || selector == uint32(IModularAccount.accountId.selector)
                || selector == uint32(IModularAccountView.getExecutionData.selector)
                || selector == uint32(IModularAccountView.getValidationData.selector)
                || selector == uint32(UUPSUpgradeable.proxiableUUID.selector)
        );
    }

    /// @dev Check whether a function is a native function that allows global validation.
    function _isGlobalValidationAllowedNativeFunction(uint32 selector) internal pure virtual returns (bool) {
        return (
            _isWrappedNativeFunction(selector) || selector == uint32(IAccountExecute.executeUserOp.selector)
                || selector == uint32(IModularAccount.executeWithRuntimeValidation.selector)
        );
    }

    /// @dev Check whether a function is a native function that has the `wrapNativeFunction` modifier applied,
    /// which means it runs execution hooks associated with its selector.
    function _isWrappedNativeFunction(uint32 selector) internal pure virtual returns (bool) {
        return (
            selector == uint32(IModularAccount.execute.selector)
                || selector == uint32(IModularAccount.executeBatch.selector)
                || selector == uint32(IModularAccount.installExecution.selector)
                || selector == uint32(IModularAccount.installValidation.selector)
                || selector == uint32(IModularAccount.uninstallExecution.selector)
                || selector == uint32(IModularAccount.uninstallValidation.selector)
                || selector == uint32(IModularAccountBase.performCreate.selector)
                || selector == uint32(UUPSUpgradeable.upgradeToAndCall.selector)
        );
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {MAX_VALIDATION_ASSOC_HOOKS} from "@erc6900/reference-implementation/helpers/Constants.sol";
import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol";
import {
    HookConfig,
    IModularAccount,
    ModuleEntity,
    ValidationConfig,
    ValidationFlags
} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol";
import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol";
import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol";
import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol";
import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol";

import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol";
import {MemManagementLib} from "../libraries/MemManagementLib.sol";
import {ModuleInstallCommonsLib} from "../libraries/ModuleInstallCommonsLib.sol";
import {ValidationLocatorLib} from "../libraries/ValidationLocatorLib.sol";
import {ValidationStorage, getAccountStorage, toSetValue} from "./AccountStorage.sol";

/// @title Module Manager Internals
/// @author Alchemy
/// @notice This abstract contract hosts the internal installation and uninstallation methods of execution and
/// validation functions. Methods here update the account storage.
abstract contract ModuleManagerInternals is IModularAccount {
    using LinkedListSetLib for LinkedListSet;
    using ModuleEntityLib for ModuleEntity;
    using ValidationConfigLib for ValidationConfig;
    using HookConfigLib for HookConfig;

    error ArrayLengthMismatch();
    error PreValidationHookDuplicate();
    error ValidationEntityIdInUse();
    error ValidationAlreadySet(bytes4 selector, ModuleEntity validationFunction);
    error ValidationAssocHookLimitExceeded();

    function _setValidationFunction(
        ValidationStorage storage validationStorage,
        ValidationConfig validationConfig,
        bytes4[] calldata selectors
    ) internal {
        // To allow for flag updates and appending hooks and selectors, two cases should be considered:
        // - stored module address is zero - store the new validation module address
        // - stored module address already holds the address of the validation module being installed - update
        // flags and selectors.
        // If the stored module address does not match, revert, as the validation entity ID must be unique over the
        // account.

        address storedAddress = validationStorage.module;
        (address moduleAddress,, ValidationFlags validationFlags) = validationConfig.unpackUnderlying();

        if (storedAddress == address(0)) {
            validationStorage.module = moduleAddress;
        } else if (storedAddress != moduleAddress) {
            revert ValidationEntityIdInUse();
        }

        validationStorage.validationFlags = validationFlags;

        uint256 length = selectors.length;
        for (uint256 i = 0; i < length; ++i) {
            bytes4 selector = selectors[i];
            if (!validationStorage.selectors.tryAdd(toSetValue(selector))) {
                revert ValidationAlreadySet(selector, validationConfig.moduleEntity());
            }
        }
    }

    function _removeValidationFunction(ValidationStorage storage validationStorage) internal {
        validationStorage.module = address(0);
        validationStorage.validationFlags = ValidationFlags.wrap(0);
        validationStorage.validationHookCount = 0;
        validationStorage.executionHookCount = 0;
    }

    function _installValidation(
        ValidationConfig validationConfig,
        bytes4[] calldata selectors,
        bytes calldata installData,
        bytes[] calldata hooks
    ) internal {
        ValidationStorage storage _validationStorage =
            getAccountStorage().validationStorage[ValidationLocatorLib.configToLookupKey(validationConfig)];

        _setValidationFunction(_validationStorage, validationConfig, selectors);

        uint256 length = hooks.length;
        for (uint256 i = 0; i < length; ++i) {
            HookConfig hookConfig = HookConfig.wrap(bytes25(hooks[i][:25]));
            bytes calldata hookData = hooks[i][25:];

            if (hookConfig.isValidationHook()) {
                // Increment the stored length of validation hooks, and revert if the limit is exceeded.

                // Safety:
                //     validationHookCount is uint8, so math operations here should never overflow
                unchecked {
                    if (uint256(_validationStorage.validationHookCount) + 1 > MAX_VALIDATION_ASSOC_HOOKS) {
                        revert ValidationAssocHookLimitExceeded();
                    }

                    ++_validationStorage.validationHookCount;
                }

                if (!_validationStorage.validationHooks.tryAdd(toSetValue(hookConfig))) {
                    revert PreValidationHookDuplicate();
                }

                ModuleInstallCommonsLib.onInstall(
                    hookConfig.module(), hookData, type(IValidationHookModule).interfaceId
                );
            } else {
                // Hook is an execution hook

                // Safety:
                //     validationHookCount is uint8, so math operations here should never overflow
                unchecked {
                    if (uint256(_validationStorage.executionHookCount) + 1 > MAX_VALIDATION_ASSOC_HOOKS) {
                        revert ValidationAssocHookLimitExceeded();
                    }

                    ++_validationStorage.executionHookCount;
                }

                ModuleInstallCommonsLib.addExecHooks(_validationStorage.executionHooks, hookConfig);
                ModuleInstallCommonsLib.onInstall(
                    hookConfig.module(), hookData, type(IExecutionHookModule).interfaceId
                );
            }
        }

        ModuleInstallCommonsLib.onInstall(
            validationConfig.module(), installData, type(IValidationModule).interfaceId
        );
        emit ValidationInstalled(validationConfig.module(), validationConfig.entityId());
    }

    function _uninstallValidation(
        ModuleEntity validationFunction,
        bytes calldata uninstallData,
        bytes[] calldata hookUninstallDatas
    ) internal {
        ValidationStorage storage _validationStorage =
            getAccountStorage().validationStorage[ValidationLocatorLib.moduleEntityToLookupKey(validationFunction)];
        bool onUninstallSuccess = true;

        // Send `onUninstall` to hooks
        if (hookUninstallDatas.length > 0) {
            HookConfig[] memory execHooks = MemManagementLib.loadExecHooks(_validationStorage);
            HookConfig[] memory validationHooks = MemManagementLib.loadValidationHooks(_validationStorage);

            // If any uninstall data is provided, assert it is of the correct length.
            if (hookUninstallDatas.length != validationHooks.length + execHooks.length) {
                revert ArrayLengthMismatch();
            }

            // Hook uninstall data is provided in the order of pre validation hooks, then execution hooks.
            uint256 hookIndex = 0;
            uint256 length = validationHooks.length;
            for (uint256 i = 0; i < length; ++i) {
                bytes calldata hookData = hookUninstallDatas[hookIndex];
                (address hookModule,) = ModuleEntityLib.unpack(validationHooks[i].moduleEntity());
                onUninstallSuccess =
                    onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(hookModule, hookData);
                hookIndex++;
            }

            length = execHooks.length;
            for (uint256 i = 0; i < length; ++i) {
                bytes calldata hookData = hookUninstallDatas[hookIndex];
                address hookModule = execHooks[i].module();
                onUninstallSuccess =
                    onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(hookModule, hookData);
                hookIndex++;
            }
        }

        // Clear all stored hooks. The lengths of the hooks are cleared in `_removeValidationFunction`.
        _validationStorage.validationHooks.clear();
        _validationStorage.executionHooks.clear();

        // Clear selectors
        _validationStorage.selectors.clear();

        // Clear validation function data.
        // Must be done at the end, because the hook lengths are accessed in the loop above.
        _removeValidationFunction(_validationStorage);

        (address module, uint32 entityId) = ModuleEntityLib.unpack(validationFunction);
        onUninstallSuccess = onUninstallSuccess && ModuleInstallCommonsLib.onUninstall(module, uninstallData);

        emit ValidationUninstalled(module, entityId, onUninstallSuccess);
    }
}

// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

/// @title Token Receiver
/// @author Alchemy
/// @notice Token receiver, supports tokens callbacks to allow the account to receive supported tokens.
abstract contract TokenReceiver is IERC721Receiver, IERC1155Receiver {
    /// @inheritdoc IERC721Receiver
    function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
        return IERC721Receiver.onERC721Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155Received(address, address, uint256, uint256, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return IERC1155Receiver.onERC1155Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return IERC1155Receiver.onERC1155BatchReceived.selector;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.20;

import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Safe Wallet (previously Gnosis Safe).
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
        return
            (error == ECDSA.RecoverError.NoError && recovered == signer) ||
            isValidERC1271SignatureNow(signer, hash, signature);
    }

    /**
     * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
     * against the signer smart contract using ERC1271.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidERC1271SignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
        );
        return (success &&
            result.length >= 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

File 51 of 70 : Constants.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

import {ModuleEntity} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";

import {ValidationLookupKey} from "../libraries/ValidationLocatorLib.sol";

// Magic value for the ModuleEntity of the fallback validation for SemiModularAccount.
ModuleEntity constant FALLBACK_VALIDATION = ModuleEntity.wrap(bytes24(0));

// Magic value for the validation entity id of the fallback validation for SemiModularAccount.
uint32 constant FALLBACK_VALIDATION_ID = uint32(0);

// Magic value for the ValidationLookupKey of the fallback validation for SemiModularAccount.
ValidationLookupKey constant FALLBACK_VALIDATION_LOOKUP_KEY = ValidationLookupKey.wrap(uint168(0));

File 52 of 70 : SignatureType.sol
// This file is part of Modular Account.
//
// Copyright 2024 Alchemy Insights, Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with this program. If not, see
// <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.26;

/// @notice An enum that is prepended to signatures to differentiate between EOA and contract owner signatures.
enum SignatureType {
    EOA,
    CONTRACT_OWNER
}

File 53 of 70 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

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

interface IExecutionHookModule is IModule {
    /// @notice Run the pre execution hook specified by the `entityId`.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender The caller address.
    /// @param value The call value.
    /// @param data The calldata sent. For `executeUserOp` calls, hook modules should receive the full msg.data.
    /// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned.
    function preExecutionHook(uint32 entityId, address sender, uint256 value, bytes calldata data)
        external
        returns (bytes memory);

    /// @notice Run the post execution hook specified by the `entityId`.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param preExecHookData The context returned by its associated pre execution hook.
    function postExecutionHook(uint32 entityId, bytes calldata preExecHookData) external;
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

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

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

interface IValidationHookModule is IModule {
    /// @notice Run the pre user operation validation hook specified by the `entityId`.
    /// @dev Pre user operation validation hooks MUST NOT return an authorizer value other than 0 or 1.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param userOp The user operation.
    /// @param userOpHash The user operation hash.
    /// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
    function preUserOpValidationHook(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        returns (uint256);

    /// @notice Run the pre runtime validation hook specified by the `entityId`.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender The caller address.
    /// @param value The call value.
    /// @param data The calldata sent.
    /// @param authorization Additional data for the hook to use.
    function preRuntimeValidationHook(
        uint32 entityId,
        address sender,
        uint256 value,
        bytes calldata data,
        bytes calldata authorization
    ) external;

    /// @notice Run the pre signature validation hook specified by the `entityId`.
    /// @dev To indicate the call should revert, the function MUST revert.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender The caller address.
    /// @param hash The hash of the message being signed.
    /// @param signature The signature of the message.
    function preSignatureValidationHook(uint32 entityId, address sender, bytes32 hash, bytes calldata signature)
        external
        view;
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

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

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

interface IValidationModule is IModule {
    /// @notice Run the user operation validation function specified by the `entityId`.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param userOp The user operation.
    /// @param userOpHash The user operation hash.
    /// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
    function validateUserOp(uint32 entityId, PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        returns (uint256);

    /// @notice Run the runtime validation function specified by the `entityId`.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param account the account to validate for.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender The caller address.
    /// @param value The call value.
    /// @param data The calldata sent.
    /// @param authorization Additional data for the validation function to use.
    function validateRuntime(
        address account,
        uint32 entityId,
        address sender,
        uint256 value,
        bytes calldata data,
        bytes calldata authorization
    ) external;

    /// @notice Validates a signature using ERC-1271.
    /// @dev To indicate the entire call should revert, the function MUST revert.
    /// @param account the account to validate for.
    /// @param entityId An identifier that routes the call to different internal implementations, should there
    /// be more than one.
    /// @param sender the address that sent the ERC-1271 request to the smart account
    /// @param hash the hash of the ERC-1271 request
    /// @param signature the signature of the ERC-1271 request
    /// @return The ERC-1271 `MAGIC_VALUE` if the signature is valid, or 0xFFFFFFFF if invalid.
    function validateSignature(
        address account,
        uint32 entityId,
        address sender,
        bytes32 hash,
        bytes calldata signature
    ) external view returns (bytes4);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

import "./PackedUserOperation.sol";

/**
 * The interface exposed by a paymaster contract, who agrees to pay the gas for user's operations.
 * A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.
 */
interface IPaymaster {
    enum PostOpMode {
        // User op succeeded.
        opSucceeded,
        // User op reverted. Still has to pay for gas.
        opReverted,
        // Only used internally in the EntryPoint (cleanup after postOp reverts). Never calling paymaster with this value
        postOpReverted
    }

    /**
     * Payment validation: check if paymaster agrees to pay.
     * Must verify sender is the entryPoint.
     * Revert to reject this request.
     * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted).
     * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns.
     * @param userOp          - The user operation.
     * @param userOpHash      - Hash of the user's request data.
     * @param maxCost         - The maximum cost of this transaction (based on maximum gas and gas price from userOp).
     * @return context        - Value to send to a postOp. Zero length to signify postOp is not required.
     * @return validationData - Signature and time-range of this operation, encoded the same as the return
     *                          value of validateUserOperation.
     *                          <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
     *                                                    other values are invalid for paymaster.
     *                          <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
     *                          <6-byte> validAfter - first timestamp this operation is valid
     *                          Note that the validation code cannot use block.timestamp (or block.number) directly.
     */
    function validatePaymasterUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 maxCost
    ) external returns (bytes memory context, uint256 validationData);

    /**
     * Post-operation handler.
     * Must verify sender is the entryPoint.
     * @param mode          - Enum with the following options:
     *                        opSucceeded - User operation succeeded.
     *                        opReverted  - User op reverted. The paymaster still has to pay for gas.
     *                        postOpReverted - never passed in a call to postOp().
     * @param context       - The context value returned by validatePaymasterUserOp
     * @param actualGasCost - Actual gas used so far (without this postOp call).
     * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas
     *                        and maxPriorityFee (and basefee)
     *                        It is not the same as tx.gasprice, which is what the bundler pays.
     */
    function postOp(
        PostOpMode mode,
        bytes calldata context,
        uint256 actualGasCost,
        uint256 actualUserOpFeePerGas
    ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
            !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     */
    function getSupportedInterfaces(
        address account,
        bytes4[] memory interfaceIds
    ) internal view returns (bool[] memory) {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     *
     * Some precompiled contracts will falsely indicate support for a given interface, so caution
     * should be exercised when using this function.
     *
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

File 59 of 70 : Constants.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

// Index marking the start of the data for the validation function.
uint8 constant RESERVED_VALIDATION_DATA_INDEX = type(uint8).max;

// Maximum number of validation-associated hooks that can be registered.
uint8 constant MAX_VALIDATION_ASSOC_HOOKS = type(uint8).max;

// Magic value for the Entity ID of direct call validation.
uint32 constant DIRECT_CALL_VALIDATION_ENTITY_ID = type(uint32).max;

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import {HookConfig, ModuleEntity, ValidationFlags} from "../interfaces/IModularAccount.sol";

/// @dev Represents data associated with a specific function selector.
struct ExecutionDataView {
    // The module that implements this execution function.
    // If this is a native function, the address must be the address of the account.
    address module;
    // Whether or not the function needs runtime validation, or can be called by anyone. The function can still be
    // state changing if this flag is set to true.
    // Note that even if this is set to true, user op validation will still be required, otherwise anyone could
    // drain the account of native tokens by wasting gas.
    bool skipRuntimeValidation;
    // Whether or not a global validation function may be used to validate this function.
    bool allowGlobalValidation;
    // The execution hooks for this function selector.
    HookConfig[] executionHooks;
}

struct ValidationDataView {
    // ValidationFlags layout:
    // 0b00000___ // unused
    // 0b_____A__ // isGlobal
    // 0b______B_ // isSignatureValidation
    // 0b_______C // isUserOpValidation
    ValidationFlags validationFlags;
    // The validation hooks for this validation function.
    HookConfig[] validationHooks;
    // Execution hooks to run with this validation function.
    HookConfig[] executionHooks;
    // The set of selectors that may be validated by this validation function.
    bytes4[] selectors;
}

interface IModularAccountView {
    /// @notice Get the execution data for a selector.
    /// @dev If the selector is a native function, the module address will be the address of the account.
    /// @param selector The selector to get the data for.
    /// @return The execution data for this selector.
    function getExecutionData(bytes4 selector) external view returns (ExecutionDataView memory);

    /// @notice Get the validation data for a validation function.
    /// @dev If the selector is a native function, the module address will be the address of the account.
    /// @param validationFunction The validation function to get the data for.
    /// @return The validation data for this validation function.
    function getValidationData(ModuleEntity validationFunction)
        external
        view
        returns (ValidationDataView memory);
}

File 63 of 70 : IAccount.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;

import "./PackedUserOperation.sol";

interface IAccount {
    /**
     * Validate user's signature and nonce
     * the entryPoint will make the call to the recipient only if this validation call returns successfully.
     * signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
     * This allows making a "simulation call" without a valid signature
     * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
     *
     * @dev Must validate caller is the entryPoint.
     *      Must validate the signature and nonce
     * @param userOp              - The operation that is about to be executed.
     * @param userOpHash          - Hash of the user's request data. can be used as the basis for signature.
     * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint.
     *                              This is the minimum amount to transfer to the sender(entryPoint) to be
     *                              able to make the call. The excess is left as a deposit in the entrypoint
     *                              for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()".
     *                              In case there is a paymaster in the request (or the current deposit is high
     *                              enough), this value will be zero.
     * @return validationData       - Packaged ValidationData structure. use `_packValidationData` and
     *                              `_unpackValidationData` to encode and decode.
     *                              <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
     *                                 otherwise, an address of an "authorizer" contract.
     *                              <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite"
     *                              <6-byte> validAfter - First timestamp this operation is valid
     *                                                    If an account doesn't use time-range, it is enough to
     *                                                    return SIG_VALIDATION_FAILED value (1) for signature failure.
     *                              Note that the validation code cannot use block.timestamp (or block.number) directly.
     */
    function validateUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 missingAccountFunds
    ) external returns (uint256 validationData);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.20;

import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 */
abstract contract UUPSUpgradeable is IERC1822Proxiable {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable __self = address(this);

    /**
     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
     * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
     * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
     * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
     * during an upgrade.
     */
    string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

    /**
     * @dev The call is from an unauthorized context.
     */
    error UUPSUnauthorizedCallContext();

    /**
     * @dev The storage `slot` is unsupported as a UUID.
     */
    error UUPSUnsupportedProxiableUUID(bytes32 slot);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        _checkProxy();
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        _checkNotDelegated();
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual notDelegated returns (bytes32) {
        return ERC1967Utils.IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data);
    }

    /**
     * @dev Reverts if the execution is not performed via delegatecall or the execution
     * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
     * See {_onlyProxy}.
     */
    function _checkProxy() internal view virtual {
        if (
            address(this) == __self || // Must be called through delegatecall
            ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
        ) {
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Reverts if the execution is performed via delegatecall.
     * See {notDelegated}.
     */
    function _checkNotDelegated() internal view virtual {
        if (address(this) != __self) {
            // Must not be called through delegatecall
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
     *
     * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
     * is expected to be the implementation slot in ERC1967.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
            if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                revert UUPSUnsupportedProxiableUUID(slot);
            }
            ERC1967Utils.upgradeToAndCall(newImplementation, data);
        } catch {
            // The implementation is not UUPS
            revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 67 of 70 : draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)

pragma solidity ^0.8.20;

import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 */
library ERC1967Utils {
    // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
    // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev The `implementation` of the proxy is invalid.
     */
    error ERC1967InvalidImplementation(address implementation);

    /**
     * @dev The `admin` of the proxy is invalid.
     */
    error ERC1967InvalidAdmin(address admin);

    /**
     * @dev The `beacon` of the proxy is invalid.
     */
    error ERC1967InvalidBeacon(address beacon);

    /**
     * @dev An upgrade function sees `msg.value > 0` that may be lost.
     */
    error ERC1967NonPayable();

    /**
     * @dev Returns the current implementation address.
     */
    function getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        if (newImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(newImplementation);
        }
        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Performs implementation upgrade with additional setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);

        if (data.length > 0) {
            Address.functionDelegateCall(newImplementation, data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
     */
    function getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        if (newAdmin == address(0)) {
            revert ERC1967InvalidAdmin(address(0));
        }
        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {IERC1967-AdminChanged} event.
     */
    function changeAdmin(address newAdmin) internal {
        emit AdminChanged(getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        if (newBeacon.code.length == 0) {
            revert ERC1967InvalidBeacon(newBeacon);
        }

        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;

        address beaconImplementation = IBeacon(newBeacon).implementation();
        if (beaconImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(beaconImplementation);
        }
    }

    /**
     * @dev Change the beacon and trigger a setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-BeaconUpgraded} event.
     *
     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
     * efficiency.
     */
    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);

        if (data.length > 0) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
     * if an upgrade doesn't perform an initialization call.
     */
    function _checkNonPayable() private {
        if (msg.value > 0) {
            revert ERC1967NonPayable();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {UpgradeableBeacon} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "@eth-infinitism/account-abstraction/=node_modules/account-abstraction/contracts/",
    "account-abstraction/=node_modules/account-abstraction/contracts/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@alchemy/light-account/=lib/light-account/",
    "solady/=node_modules/solady/src/",
    "@erc6900/reference-implementation/=node_modules/@erc6900/reference-implementation/src/",
    "forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "webauthn-sol/=lib/webauthn-sol/",
    "FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/",
    "openzeppelin-contracts/=lib/webauthn-sol/lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entryPoint","type":"address"},{"internalType":"contract ModularAccount","name":"_accountImpl","type":"address"},{"internalType":"contract SemiModularAccountBytecode","name":"_semiModularImpl","type":"address"},{"internalType":"address","name":"_singleSignerValidationModule","type":"address"},{"internalType":"address","name":"_webAuthnValidationModule","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidAction","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"salt","type":"uint256"}],"name":"ModularAccountDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"salt","type":"uint256"}],"name":"SemiModularAccountDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"ownerX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"ownerY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"salt","type":"uint256"}],"name":"WebAuthnModularAccountDeployed","type":"event"},{"inputs":[],"name":"ACCOUNT_IMPL","outputs":[{"internalType":"contract ModularAccount","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENTRY_POINT","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEMI_MODULAR_ACCOUNT_IMPL","outputs":[{"internalType":"contract SemiModularAccountBytecode","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SINGLE_SIGNER_VALIDATION_MODULE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEBAUTHN_VALIDATION_MODULE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"unstakeDelay","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"createAccount","outputs":[{"internalType":"contract ModularAccount","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"createSemiModularAccount","outputs":[{"internalType":"contract SemiModularAccountBytecode","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ownerX","type":"uint256"},{"internalType":"uint256","name":"ownerY","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"createWebAuthnAccount","outputs":[{"internalType":"contract ModularAccount","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"getAddressSemiModular","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ownerX","type":"uint256"},{"internalType":"uint256","name":"ownerY","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"getAddressWebAuthn","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"getSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"ownerX","type":"uint256"},{"internalType":"uint256","name":"ownerY","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint32","name":"entityId","type":"uint32"}],"name":"getSaltWebAuthn","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610120346101aa57601f611bdf38819003918201601f19168301916001600160401b038311848410176101af5780849260c0946040528339810103126101aa578051906001600160a01b03821682036101aa5760208101516001600160a01b03811681036101aa5760408201516001600160a01b03811681036101aa57610088606084016101c5565b91610095608085016101c5565b936001600160a01b03906100ab9060a0016101c5565b1694851561019457600180546001600160a01b0319908116909155600080549182168817815560405197916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a360c05260805260a05260e05261010052611a0590816101da8239608051818181610472015281816107cd01528181610fe50152611310015260a05181818161057301528181610bac0152610f02015260c0518181816105ef015281816106dc01528181610a6501526113a4015260e0518181816108b3015261128501526101005181818161015901526110b90152f35b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101aa5756fe6080604052600436101561001257600080fd5b6000803560e01c80630396cb601461134857806303c7e13114611334578063121ee541146112c55780632a7867c2146112a95780632f8aae1d1461123a578063421a21e01461121d5780634659e0e314610f5c5780636aa3406314610e2b578063715018a614610dcc57806379ba509714610cc45780638b4e464e14610ada5780638da5cb5b14610a8957806394430fa514610a1a578063afa63a1014610744578063bb9fe6bf1461068d578063c23a5cea14610597578063c95ff21e14610528578063d7f8ee7714610436578063d9caed1214610291578063e30c39781461023f578063f2fde38b146101805763f96477ae1461010f57600080fd5b3461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b80fd5b503461017d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5773ffffffffffffffffffffffffffffffffffffffff6101cd61142f565b6101d56118ab565b16807fffffffffffffffffffffffff0000000000000000000000000000000000000000600154161760015573ffffffffffffffffffffffffffffffffffffffff8254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b503461017d5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57806102ca61142f565b60243573ffffffffffffffffffffffffffffffffffffffff8116809103610432576102f36118ab565b8061035057508180809273ffffffffffffffffffffffffffffffffffffffff4791165af161031f61184d565b50156103285780f35b807f90b8ec180000000000000000000000000000000000000000000000000000000060049252fd5b91806103c89260405173ffffffffffffffffffffffffffffffffffffffff60208201927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248201526044356044820152604481526103b3606482611502565b519082865af16103c161184d565b908361195b565b805190811515918261040a575b50506103df575080f35b7f5274afe7000000000000000000000000000000000000000000000000000000008252600452602490fd5b819250906020918101031261042e576020015180159081150361042e5738806103d5565b8280fd5b5050fd5b503461017d57602061050a61045661044d366114b9565b92919091611653565b309061050573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690604051917fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076604052616009602052601e5268603d3d8160223d3973600a52605f602120916040526000606052565b61193a565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461017d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57806105d061142f565b6105d86118ab565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690813b156104325773ffffffffffffffffffffffffffffffffffffffff602484928360405195869485937fc23a5cea0000000000000000000000000000000000000000000000000000000085521660048401525af18015610682576106715750f35b8161067b91611502565b61017d5780f35b6040513d84823e3d90fd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d576106c46118ab565b8073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610741578180916004604051809481937fbb9fe6bf0000000000000000000000000000000000000000000000000000000083525af18015610682576106715750f35b50fd5b503461017d5761075336611457565b6107618183859496956115e3565b928092604051937fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016601e5268603d3d8160223d3973600a52605f60212060358601523060581b855260ff85538560158601526055852095863b156109fe57505060015b846040528260605215610857575b60208573ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff9063ffffffff84166020860152169283604082015260408152610890606082611502565b73ffffffffffffffffffffffffffffffffffffffff8516926703000000000000007f000000000000000000000000000000000000000000000000000000000000000060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660409290921b6bffffffff00000000000000001691909117670400000000000000177fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000016176040519061094b602083611502565b838252600036813761095b6116a4565b853b156109fa579061099d85939260405195869485947fe919a62300000000000000000000000000000000000000000000000000000000865260048601611737565b038183875af18015610682576109e5575b50507f965f7f47ad3d6fb75196915b245b826100063bf2d9bc0a5e5304a41843baf97f60208095604051908152a338808080610836565b6109f0828092611502565b61017d57806109ae565b8480fd5b909550605f602184f5948561082857633011642583526004601cfd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b503461017d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57610b1261142f565b602435610b1f8183611572565b91610b29816118fa565b92849060606040519580518091816020858b01920160045afa507fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360408801527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076602088015261600960165273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166014528060381b6afe61003d3d8160233d39730161ffc2821152601651875260ff8853018086206035523060601b600152816015526055872095863b15610ca157505050506020936001905b60355215610c41575b505073ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff9060405192835216907fd32049610f0cd3babd266cf338d726cc8c34c8ff97356c0f33c13fa59962ac928473ffffffffffffffffffffffffffffffffffffffff851692a33880610c21565b909192955086f5928315610cb757602094610c18565b633011642585526004601cfd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d576001543373ffffffffffffffffffffffffffffffffffffffff821603610da0577fffffffffffffffffffffffff0000000000000000000000000000000000000000166001558054337fffffffffffffffffffffffff0000000000000000000000000000000000000000821617825573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f118cdaa700000000000000000000000000000000000000000000000000000000815233600452fd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57600490610e066118ab565b7f4a7f394f000000000000000000000000000000000000000000000000000000008152fd5b503461017d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602090610e6661142f565b90610e7c610e7660243584611572565b926118fa565b9160405183519261ffc284113d3d3e805b848110610f48575061050a94507fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360408301527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768683015261600960165273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166014528360381b6961003d3d8160233d397301905260165181526060309301902061193a565b858101870151838201606001528601610e8d565b503461017d57610f6b366114b9565b610f7a81838587959897611653565b9380604051907fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016601e5268603d3d8160223d3973600a52605f60212060358301523060581b825260ff82538660158301526055822096873b1561120157505060015b81604052826060521561106f575b60208673ffffffffffffffffffffffffffffffffffffffff60405191168152f35b63ffffffff8316602082015283604082015284606082015260608152611096608082611502565b73ffffffffffffffffffffffffffffffffffffffff8616926703000000000000007f000000000000000000000000000000000000000000000000000000000000000060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660409290921b6bffffffff00000000000000001691909117670400000000000000177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000161760405190611151602083611502565b83825260003681376111616116a4565b853b156109fa57906111a385939260405195869485947fe919a62300000000000000000000000000000000000000000000000000000000865260048601611737565b038183875af18015610682576111ec575b50507f3c550e8add4d9c37ca7c0b494c244828e4600acf1a41a582815d37b6a039557760208096604051908152a4388080808061104e565b6111f7828092611502565b61017d57806111b4565b909650605f602184f5958661104057633011642583526004601cfd5b503461017d57602061050a61045661123436611457565b916115e3565b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461017d5760206112bd61044d366114b9565b604051908152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461017d5760206112bd61123436611457565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5760043563ffffffff811680910361142b5761138c6118ab565b8173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b1561142b5781906024604051809581937f0396cb60000000000000000000000000000000000000000000000000000000008352600483015234905af1801561141e576114105780f35b61141991611502565b388180f35b50604051903d90823e3d90fd5b5080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361145257565b600080fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126114525760043573ffffffffffffffffffffffffffffffffffffffff8116810361145257906024359060443563ffffffff811681036114525790565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126114525760043590602435906044359060643563ffffffff811681036114525790565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761154357604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90604051907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602083019360601b16835260348201527fffffffff000000000000000000000000000000000000000000000000000000006054820152603881526115dd605882611502565b51902090565b917fffffffff0000000000000000000000000000000000000000000000000000000090604051927fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602085019560601b168552603484015260e01b166054820152603881526115dd605882611502565b927fffffffff00000000000000000000000000000000000000000000000000000000919260405193602085019586526040850152606084015260e01b166080820152606481526115dd608482611502565b604051906116b3602083611502565b600080835282815b8281106116c757505050565b8060606020809385010152016116bb565b919082519283825260005b8481106117225750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b806020809284010151828286010152016116e3565b929190917fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000006080850193168452608060208501528151809352602060a0850192019260005b818110611815575050611797925083820360408501526116d8565b906060818303910152815180825260208201916020808360051b8301019401926000915b8383106117ca57505050505090565b9091929394602080611806837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0866001960301875289516116d8565b970193019301919392906117bb565b84517fffffffff000000000000000000000000000000000000000000000000000000001684526020948501949093019260010161177c565b3d156118a6573d9067ffffffffffffffff8211611543576040519161189a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611502565b82523d6000602084013e565b606090565b73ffffffffffffffffffffffffffffffffffffffff6000541633036118cc57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519160601b16602082015260148152611937603482611502565b90565b91909160ff60005360355260601b6001526015526055600020906000603552565b9061199a575080511561197057805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b815115806119ef575b6119ab575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156119a356fea164736f6c634300081a000a0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03200000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f000000000000000000000000000000000000c5a9089039570dd36455b5c0738300000000000000000000000000000000000099de0bf6fa90deb851e2a2df7d830000000000000000000000000000000000001d9d34e07d9834274df9ae575217000000000000000000000000ddf32240b4ca3184de7ec8f0d5aba27dec8b7a5c

Deployed Bytecode

0x6080604052600436101561001257600080fd5b6000803560e01c80630396cb601461134857806303c7e13114611334578063121ee541146112c55780632a7867c2146112a95780632f8aae1d1461123a578063421a21e01461121d5780634659e0e314610f5c5780636aa3406314610e2b578063715018a614610dcc57806379ba509714610cc45780638b4e464e14610ada5780638da5cb5b14610a8957806394430fa514610a1a578063afa63a1014610744578063bb9fe6bf1461068d578063c23a5cea14610597578063c95ff21e14610528578063d7f8ee7714610436578063d9caed1214610291578063e30c39781461023f578063f2fde38b146101805763f96477ae1461010f57600080fd5b3461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000001d9d34e07d9834274df9ae575217168152f35b80fd5b503461017d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5773ffffffffffffffffffffffffffffffffffffffff6101cd61142f565b6101d56118ab565b16807fffffffffffffffffffffffff0000000000000000000000000000000000000000600154161760015573ffffffffffffffffffffffffffffffffffffffff8254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b503461017d5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57806102ca61142f565b60243573ffffffffffffffffffffffffffffffffffffffff8116809103610432576102f36118ab565b8061035057508180809273ffffffffffffffffffffffffffffffffffffffff4791165af161031f61184d565b50156103285780f35b807f90b8ec180000000000000000000000000000000000000000000000000000000060049252fd5b91806103c89260405173ffffffffffffffffffffffffffffffffffffffff60208201927fa9059cbb0000000000000000000000000000000000000000000000000000000084521660248201526044356044820152604481526103b3606482611502565b519082865af16103c161184d565b908361195b565b805190811515918261040a575b50506103df575080f35b7f5274afe7000000000000000000000000000000000000000000000000000000008252600452602490fd5b819250906020918101031261042e576020015180159081150361042e5738806103d5565b8280fd5b5050fd5b503461017d57602061050a61045661044d366114b9565b92919091611653565b309061050573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f1690604051917fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076604052616009602052601e5268603d3d8160223d3973600a52605f602120916040526000606052565b61193a565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000c5a9089039570dd36455b5c07383168152f35b503461017d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57806105d061142f565b6105d86118ab565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321690813b156104325773ffffffffffffffffffffffffffffffffffffffff602484928360405195869485937fc23a5cea0000000000000000000000000000000000000000000000000000000085521660048401525af18015610682576106715750f35b8161067b91611502565b61017d5780f35b6040513d84823e3d90fd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d576106c46118ab565b8073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03216803b15610741578180916004604051809481937fbb9fe6bf0000000000000000000000000000000000000000000000000000000083525af18015610682576106715750f35b50fd5b503461017d5761075336611457565b6107618183859496956115e3565b928092604051937fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f16601e5268603d3d8160223d3973600a52605f60212060358601523060581b855260ff85538560158601526055852095863b156109fe57505060015b846040528260605215610857575b60208573ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff9063ffffffff84166020860152169283604082015260408152610890606082611502565b73ffffffffffffffffffffffffffffffffffffffff8516926703000000000000007f00000000000000000000000000000000000099de0bf6fa90deb851e2a2df7d8360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660409290921b6bffffffff00000000000000001691909117670400000000000000177fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000016176040519061094b602083611502565b838252600036813761095b6116a4565b853b156109fa579061099d85939260405195869485947fe919a62300000000000000000000000000000000000000000000000000000000865260048601611737565b038183875af18015610682576109e5575b50507f965f7f47ad3d6fb75196915b245b826100063bf2d9bc0a5e5304a41843baf97f60208095604051908152a338808080610836565b6109f0828092611502565b61017d57806109ae565b8480fd5b909550605f602184f5948561082857633011642583526004601cfd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032168152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b503461017d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57610b1261142f565b602435610b1f8183611572565b91610b29816118fa565b92849060606040519580518091816020858b01920160045afa507fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360408801527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076602088015261600960165273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000c5a9089039570dd36455b5c07383166014528060381b6afe61003d3d8160233d39730161ffc2821152601651875260ff8853018086206035523060601b600152816015526055872095863b15610ca157505050506020936001905b60355215610c41575b505073ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff9060405192835216907fd32049610f0cd3babd266cf338d726cc8c34c8ff97356c0f33c13fa59962ac928473ffffffffffffffffffffffffffffffffffffffff851692a33880610c21565b909192955086f5928315610cb757602094610c18565b633011642585526004601cfd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d576001543373ffffffffffffffffffffffffffffffffffffffff821603610da0577fffffffffffffffffffffffff0000000000000000000000000000000000000000166001558054337fffffffffffffffffffffffff0000000000000000000000000000000000000000821617825573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6024827f118cdaa700000000000000000000000000000000000000000000000000000000815233600452fd5b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57600490610e066118ab565b7f4a7f394f000000000000000000000000000000000000000000000000000000008152fd5b503461017d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602090610e6661142f565b90610e7c610e7660243584611572565b926118fa565b9160405183519261ffc284113d3d3e805b848110610f48575061050a94507fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360408301527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768683015261600960165273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000c5a9089039570dd36455b5c07383166014528360381b6961003d3d8160233d397301905260165181526060309301902061193a565b858101870151838201606001528601610e8d565b503461017d57610f6b366114b9565b610f7a81838587959897611653565b9380604051907fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f16601e5268603d3d8160223d3973600a52605f60212060358301523060581b825260ff82538660158301526055822096873b1561120157505060015b81604052826060521561106f575b60208673ffffffffffffffffffffffffffffffffffffffff60405191168152f35b63ffffffff8316602082015283604082015284606082015260608152611096608082611502565b73ffffffffffffffffffffffffffffffffffffffff8616926703000000000000007f0000000000000000000000000000000000001d9d34e07d9834274df9ae57521760601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660409290921b6bffffffff00000000000000001691909117670400000000000000177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000161760405190611151602083611502565b83825260003681376111616116a4565b853b156109fa57906111a385939260405195869485947fe919a62300000000000000000000000000000000000000000000000000000000865260048601611737565b038183875af18015610682576111ec575b50507f3c550e8add4d9c37ca7c0b494c244828e4600acf1a41a582815d37b6a039557760208096604051908152a4388080808061104e565b6111f7828092611502565b61017d57806111b4565b909650605f602184f5958661104057633011642583526004601cfd5b503461017d57602061050a61045661123436611457565b916115e3565b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000099de0bf6fa90deb851e2a2df7d83168152f35b503461017d5760206112bd61044d366114b9565b604051908152f35b503461017d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d57602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f168152f35b503461017d5760206112bd61123436611457565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017d5760043563ffffffff811680910361142b5761138c6118ab565b8173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0321691823b1561142b5781906024604051809581937f0396cb60000000000000000000000000000000000000000000000000000000008352600483015234905af1801561141e576114105780f35b61141991611502565b388180f35b50604051903d90823e3d90fd5b5080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361145257565b600080fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126114525760043573ffffffffffffffffffffffffffffffffffffffff8116810361145257906024359060443563ffffffff811681036114525790565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126114525760043590602435906044359060643563ffffffff811681036114525790565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761154357604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90604051907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602083019360601b16835260348201527fffffffff000000000000000000000000000000000000000000000000000000006054820152603881526115dd605882611502565b51902090565b917fffffffff0000000000000000000000000000000000000000000000000000000090604051927fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602085019560601b168552603484015260e01b166054820152603881526115dd605882611502565b927fffffffff00000000000000000000000000000000000000000000000000000000919260405193602085019586526040850152606084015260e01b166080820152606481526115dd608482611502565b604051906116b3602083611502565b600080835282815b8281106116c757505050565b8060606020809385010152016116bb565b919082519283825260005b8481106117225750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b806020809284010151828286010152016116e3565b929190917fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000006080850193168452608060208501528151809352602060a0850192019260005b818110611815575050611797925083820360408501526116d8565b906060818303910152815180825260208201916020808360051b8301019401926000915b8383106117ca57505050505090565b9091929394602080611806837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0866001960301875289516116d8565b970193019301919392906117bb565b84517fffffffff000000000000000000000000000000000000000000000000000000001684526020948501949093019260010161177c565b3d156118a6573d9067ffffffffffffffff8211611543576040519161189a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611502565b82523d6000602084013e565b606090565b73ffffffffffffffffffffffffffffffffffffffff6000541633036118cc57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519160601b16602082015260148152611937603482611502565b90565b91909160ff60005360355260601b6001526015526055600020906000603552565b9061199a575080511561197057805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b815115806119ef575b6119ab575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156119a356fea164736f6c634300081a000a

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

0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03200000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f000000000000000000000000000000000000c5a9089039570dd36455b5c0738300000000000000000000000000000000000099de0bf6fa90deb851e2a2df7d830000000000000000000000000000000000001d9d34e07d9834274df9ae575217000000000000000000000000ddf32240b4ca3184de7ec8f0d5aba27dec8b7a5c

-----Decoded View---------------
Arg [0] : _entryPoint (address): 0x0000000071727De22E5E9d8BAf0edAc6f37da032
Arg [1] : _accountImpl (address): 0x00000000000002377B26b1EdA7b0BC371C60DD4f
Arg [2] : _semiModularImpl (address): 0x000000000000c5A9089039570Dd36455b5C07383
Arg [3] : _singleSignerValidationModule (address): 0x00000000000099DE0BF6fA90dEB851E2A2df7d83
Arg [4] : _webAuthnValidationModule (address): 0x0000000000001D9d34E07D9834274dF9ae575217
Arg [5] : owner (address): 0xDdF32240B4ca3184De7EC8f0D5Aba27dEc8B7A5C

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Arg [1] : 00000000000000000000000000000000000002377b26b1eda7b0bc371c60dd4f
Arg [2] : 000000000000000000000000000000000000c5a9089039570dd36455b5c07383
Arg [3] : 00000000000000000000000000000000000099de0bf6fa90deb851e2a2df7d83
Arg [4] : 0000000000000000000000000000000000001d9d34e07d9834274df9ae575217
Arg [5] : 000000000000000000000000ddf32240b4ca3184de7ec8f0d5aba27dec8b7a5c


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.

OSZAR »