ETH Price: $4,329.49 (-2.74%)

Contract

0x0000000031ef4155C978d48a8A7d4EDba03b04fE

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
64516402025-07-22 14:27:3179 days ago1753194451  Contract Creation0 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
K1MeeValidator

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 999 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

import {IValidator, MODULE_TYPE_VALIDATOR} from "erc7579/interfaces/IERC7579Module.sol";
import {ISessionValidator} from "contracts/interfaces/ISessionValidator.sol";
import {EnumerableSet} from "EnumerableSet4337/EnumerableSet4337.sol";
import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
import {ERC7739Validator} from "erc7739Validator/ERC7739Validator.sol";
import {
    SIG_TYPE_SIMPLE,
    SIG_TYPE_ON_CHAIN,
    SIG_TYPE_ERC20_PERMIT,
    EIP1271_SUCCESS,
    EIP1271_FAILED,
    MODULE_TYPE_STATELESS_VALIDATOR,
    SIG_TYPE_MEE_FLOW
} from "contracts/types/Constants.sol";
// Fusion libraries - validate userOp using on-chain tx or off-chain permit
import {PermitValidatorLib} from "../lib/fusion/PermitValidatorLib.sol";
import {TxValidatorLib} from "../lib/fusion/TxValidatorLib.sol";
import {SimpleValidatorLib} from "../lib/fusion/SimpleValidatorLib.sol";
import {NoMeeFlowLib} from "../lib/fusion/NoMeeFlowLib.sol";
import {EcdsaLib} from "../lib/util/EcdsaLib.sol";

/**
 * @title K1MeeValidator
 * @dev   An ERC-7579 validator (module type 1) and stateless validator (module type 7) for the MEE stack.
 *        Supports 3 MEE modes:
 *        - Simple (Super Tx hash is signed)
 *        - On-chain Tx (Super Tx hash is appended to a regular txn and signed)
 *        - ERC-2612 Permit (Super Tx hash is pasted into deadline field of the ERC-2612 Permit and signed)
 *
 *        Further improvements:
 *        - Further gas optimizations
 *        - Use EIP-712 to make superTx hash not blind => use 7739 for the MEE 1271 flows
 *
 *        Using erc7739 for MEE flows makes no sense currently because user signs blind hashes anyways
 *        (except permit mode, but the superTx hash is still blind in it).
 *        So we just hash smart account address into the og hash for 1271 MEE flow currently.
 *        In future full scale 7739 will replace it when superTx hash is 712 and transparent.
 *
 */

contract K1MeeValidator is IValidator, ISessionValidator, ERC7739Validator {
    using EnumerableSet for EnumerableSet.AddressSet;
    /*//////////////////////////////////////////////////////////////////////////
                            CONSTANTS & STORAGE
    //////////////////////////////////////////////////////////////////////////*/

    uint256 private constant ENCODED_DATA_OFFSET = 4;
    
    /// @notice Mapping of smart account addresses to their respective owner addresses
    mapping(address => address) public smartAccountOwners;

    /// @notice Set of safe senders for each smart account
    EnumerableSet.AddressSet private _safeSenders;

    /// @notice Error to indicate that no owner was provided during installation
    error NoOwnerProvided();

    /// @notice Error to indicate that the new owner cannot be the zero address
    error ZeroAddressNotAllowed();

    /// @notice Error to indicate the module is already initialized
    error ModuleAlreadyInitialized();

    /// @notice Error to indicate that the new owner cannot be a contract address
    error NewOwnerIsNotEOA();

    /// @notice Error to indicate that the owner cannot be the zero address
    error OwnerCannotBeZeroAddress();

    /// @notice Error to indicate that the data length is invalid
    error InvalidDataLength();

    /// @notice Error to indicate that the safe senders length is invalid
    error SafeSendersLengthInvalid();

    /*//////////////////////////////////////////////////////////////////////////
                                     CONFIG
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * Initialize the module with the given data
     *
     * @param data The data to initialize the module with
     */
    function onInstall(bytes calldata data) external override {
        require(data.length != 0, NoOwnerProvided());
        require(!_isInitialized(msg.sender), ModuleAlreadyInitialized());
        address newOwner = address(bytes20(data[:20]));
        require(newOwner != address(0), OwnerCannotBeZeroAddress());
        if (_isNotEOA(newOwner)) {
            revert NewOwnerIsNotEOA();
        }
        smartAccountOwners[msg.sender] = newOwner;
        if (data.length > 20) {
            _fillSafeSenders(data[20:]);
        }
    }

    /**
     * De-initialize the module with the given data
     */
    function onUninstall(bytes calldata) external override {
        delete smartAccountOwners[msg.sender];
        _safeSenders.removeAll(msg.sender);
    }

    /// @notice Transfers ownership of the validator to a new owner
    /// @param newOwner The address of the new owner
    function transferOwnership(address newOwner) external {
        require(newOwner != address(0), ZeroAddressNotAllowed());
        if (_isNotEOA(newOwner)) {
            revert NewOwnerIsNotEOA();
        }
        smartAccountOwners[msg.sender] = newOwner;
    }

    /**
     * Check if the module is initialized
     * @param smartAccount The smart account to check
     *
     * @return true if the module is initialized, false otherwise
     */
    function isInitialized(address smartAccount) external view returns (bool) {
        return _isInitialized(smartAccount);
    }

    /// @notice Adds a safe sender to the _safeSenders list for the smart account
    function addSafeSender(address sender) external {
        _safeSenders.add(msg.sender, sender);
    }

    /// @notice Removes a safe sender from the _safeSenders list for the smart account
    function removeSafeSender(address sender) external {
        _safeSenders.remove(msg.sender, sender);
    }

    /// @notice Checks if a sender is in the _safeSenders list for the smart account
    function isSafeSender(address sender, address smartAccount) external view returns (bool) {
        return _safeSenders.contains(smartAccount, sender);
    }

    /*//////////////////////////////////////////////////////////////////////////
                                     MODULE LOGIC
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * Validates PackedUserOperation
     *
     * @param userOp UserOperation to be validated
     * @param userOpHash Hash of the UserOperation to be validated
     * @dev fallback flow => non MEE flow => no dedicated prefix introduced for the sake of compatibility.
     *      It may lead to a case where some signature turns out to have first bytes matching the prefix.
     *      However, this is very unlikely to happen and even if it does, the consequences are just
     *      that the signature is not validated which is easily solved by altering userOp => hash => sig.
     *      The userOp.signature is encoded as follows:
     *      MEE flow: [65 bytes node master signature] [4 bytes sigType] [encoded data for this validator]
     *      Non-MEE flow: [65 bytes regular secp256k1 sig]
     *
     * @return uint256 the result of the signature validation, which can be:
     *  - 0 if the signature is valid
     *  - 1 if the signature is invalid
     *  - <20-byte> aggregatorOrSigFail, <6-byte> validUntil and <6-byte> validAfter (see ERC-4337
     * for more details)
     */
    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
        external
        override
        returns (uint256)
    {   
        address owner = getOwner(userOp.sender);
        if (userOp.signature.length < ENCODED_DATA_OFFSET) {
            // if sig is short then we are sure it is a non-MEE flow
            return NoMeeFlowLib.validateUserOp(userOpHash, userOp.signature, owner);
        } else {
            bytes4 sigType = bytes4(userOp.signature[0:ENCODED_DATA_OFFSET]);
            if (sigType == SIG_TYPE_SIMPLE) {
                return SimpleValidatorLib.validateUserOp(userOpHash, userOp.signature[ENCODED_DATA_OFFSET:], owner);
            } else if (sigType == SIG_TYPE_ON_CHAIN) {
                return TxValidatorLib.validateUserOp(userOpHash, userOp.signature[ENCODED_DATA_OFFSET:userOp.signature.length], owner);
            } else if (sigType == SIG_TYPE_ERC20_PERMIT) {
                return PermitValidatorLib.validateUserOp(userOpHash, userOp.signature[ENCODED_DATA_OFFSET:], owner);
            } else {
                // fallback flow => non MEE flow => no prefix
                return NoMeeFlowLib.validateUserOp(userOpHash, userOp.signature, owner);
            }
        }
    }

    /**
     * Validates an ERC-1271 signature
     *
     * @param sender The sender of the ERC-1271 call to the account
     * @param hash The hash of the message
     * @param signature The signature of the message
     *
     * @return sigValidationResult the result of the signature validation, which can be:
     *  - EIP1271_SUCCESS if the signature is valid
     *  - EIP1271_FAILED if the signature is invalid
     */
    function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature)
        external
        view
        virtual
        override
        returns (bytes4 sigValidationResult)
    {
        if (bytes3(signature[0:3]) != SIG_TYPE_MEE_FLOW) {
            // Non MEE 7739 flow
            // goes to ERC7739Validator to apply 7739 magic and then returns back
            // to this contract's _erc1271IsValidSignatureNowCalldata() method.
            return _erc1271IsValidSignatureWithSender(sender, hash, _erc1271UnwrapSignature(signature));
        } else {
            // non-7739 flow
            // hash the SA into the `hash` to protect against two SA's with same owner vector
            return _validateSignatureForOwner(
                getOwner(msg.sender), keccak256(abi.encodePacked(hash, msg.sender)), _erc1271UnwrapSignature(signature)
            ) ? EIP1271_SUCCESS : EIP1271_FAILED;
        }
    }

    /// @notice ISessionValidator interface for smart session
    /// @param hash The hash of the data to validate
    /// @param sig The signature data
    /// @param data The data to validate against (owner address in this case)
    function validateSignatureWithData(bytes32 hash, bytes calldata sig, bytes calldata data)
        external
        view
        returns (bool validSig)
    {
        require(data.length >= 20, InvalidDataLength());
        return _validateSignatureForOwner(address(bytes20(data[:20])), hash, sig);
    }

    /**
     * Get the owner of the smart account
     * @param smartAccount The address of the smart account
     * @return The owner of the smart account
     */
    function getOwner(address smartAccount) public view returns (address) {
        address owner = smartAccountOwners[smartAccount];
        return owner == address(0) ? smartAccount : owner;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                     METADATA
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Returns the name of the module
    /// @return The name of the module
    function name() external pure returns (string memory) {
        return "K1MeeValidator";
    }

    /// @notice Returns the version of the module
    /// @return The version of the module
    /// @dev
    /// - supports appended 65-bytes signature for on-chain fusion mode
    /// - supports erc7702-delegated EOAs as owners  
    function version() external pure returns (string memory) {
        return "1.0.3";
    }

    /// @notice Checks if the module is of the specified type
    /// @param typeId The type ID to check
    /// @return True if the module is of the specified type, false otherwise
    function isModuleType(uint256 typeId) external pure returns (bool) {
        return typeId == MODULE_TYPE_VALIDATOR || typeId == MODULE_TYPE_STATELESS_VALIDATOR;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                     INTERNAL
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Internal method that does the job of validating the signature via ECDSA (secp256k1)
    /// @param owner The address of the owner
    /// @param hash The hash of the data to validate
    /// @param signature The signature data
    function _validateSignatureForOwner(address owner, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool)
    {
        bytes4 sigType = bytes4(signature[0:4]);

        if (sigType == SIG_TYPE_SIMPLE) {
            return SimpleValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
        } else if (sigType == SIG_TYPE_ON_CHAIN) {
            return TxValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
        } else if (sigType == SIG_TYPE_ERC20_PERMIT) {
            return PermitValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
        } else {
            // fallback flow => non MEE flow => no prefix
            return NoMeeFlowLib.validateSignatureForOwner(owner, hash, signature);
        }
    }

    /// @notice Checks if the smart account is initialized with an owner
    /// @param smartAccount The address of the smart account
    /// @return True if the smart account has an owner, false otherwise
    function _isInitialized(address smartAccount) private view returns (bool) {
        return smartAccountOwners[smartAccount] != address(0);
    }

    // @notice Fills the _safeSenders list from the given data
    function _fillSafeSenders(bytes calldata data) private {
        require(data.length % 20 == 0, SafeSendersLengthInvalid());
        for (uint256 i; i < data.length / 20; i++) {
            _safeSenders.add(msg.sender, address(bytes20(data[20 * i:20 * (i + 1)])));
        }
    }

    /// @notice Checks if the address is a contract
    /// @param account The address to check
    /// @return True if the address is a contract, false otherwise
    function _isNotEOA(address account) private view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        // has code and is not delegated via eip-7702
        return (size > 0) && (size != 23);
    }

    /// @dev Returns whether the `hash` and `signature` are valid.
    ///      Obtains the authorized signer's credentials and calls some
    ///      module's specific internal function to validate the signature
    ///      against credentials.
    function _erc1271IsValidSignatureNowCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        override
        returns (bool)
    {
        // call custom internal function to validate the signature against credentials
        return EcdsaLib.isValidSignature(getOwner(msg.sender), hash, signature);
    }

    /// @dev Returns whether the `sender` is considered safe, such
    /// that we don't need to use the nested EIP-712 workflow.
    /// See: https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU
    // The canonical `MulticallerWithSigner` at 0x000000000000D9ECebf3C23529de49815Dac1c4c
    // is known to include the account in the hash to be signed.
    // msg.sender = Smart Account
    // sender = 1271 og request sender
    function _erc1271CallerIsSafe(address sender) internal view virtual override returns (bool) {
        return (
            sender == 0x000000000000D9ECebf3C23529de49815Dac1c4c // MulticallerWithSigner
                || sender == msg.sender // Smart Account. Assume smart account never sends non safe eip-712 struct
                || _safeSenders.contains(msg.sender, sender)
        ); // check if sender is in _safeSenders for the Smart Account
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

interface IExecutor is IModule { }

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

    function postCheck(bytes calldata hookData) external;
}

interface IFallback is IModule { }

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

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

// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.23;

import {IModule} from "erc7579/interfaces/IERC7579Module.sol";

uint256 constant ERC7579_MODULE_TYPE_STATELESS_VALIDATOR = 7;

/**
 * ISessionValidator is a contract that validates signatures for a given session.
 * this interface expects to validate the signature in a stateless way.
 * all parameters required to validate the signature are passed in the function call.
 * Only one ISessionValidator is responsible to validate a userOp.
 * if you want to use multiple validators, you can create a ISessionValidator that aggregates multiple signatures that
 * are packed into userOp.signature
 * It is used to validate the signature of a session.
 *  hash The userOp hash
 *  sig The signature of userOp
 *  data the config data that is used to validate the signature
 */
interface ISessionValidator is IModule {
    function validateSignatureWithData(bytes32 hash, bytes calldata sig, bytes calldata data)
        external
        view
        returns (bool validSig);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "./AssociatedArrayLib.sol";

/**
 * Fork of OZ's EnumerableSet that makes all storage access ERC-4337 compliant via associated storage
 * @author zeroknots.eth (rhinestone)
 */
library EnumerableSet {
    using AssociatedArrayLib for AssociatedArrayLib.Bytes32Array;
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        AssociatedArrayLib.Bytes32Array _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => mapping(address account => uint256)) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, address account, bytes32 value) private returns (bool) {
        if (!_contains(set, account, value)) {
            set._values.push(account, value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value][account] = set._values.length(account);
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, address account, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value][account];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length(account) - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values.get(account, lastIndex);

                // Move the lastValue to the index where the value to delete is
                set._values.set(account, valueIndex, lastValue);
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue][account] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop(account);

            // Delete the tracked position for the deleted slot
            delete set._positions[value][account];

            return true;
        } else {
            return false;
        }
    }

    function _removeAll(Set storage set, address account) internal {
        // get length of the array
        uint256 len = _length(set, account);
        for (uint256 i = 1; i <= len; i++) {
            // get last value
            bytes32 value = _at(set, account, len - i);
            _remove(set, account, value);
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, address account, bytes32 value) private view returns (bool) {
        return set._positions[value][account] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set, address account) private view returns (uint256) {
        return set._values.length(account);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, address account, uint256 index) private view returns (bytes32) {
        return set._values.get(account, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set, address account) private view returns (bytes32[] memory) {
        return set._values.getAll(account);
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, address account, bytes32 value) internal returns (bool) {
        return _add(set._inner, account, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, address account, bytes32 value) internal returns (bool) {
        return _remove(set._inner, account, value);
    }

    function removeAll(Bytes32Set storage set, address account) internal {
        return _removeAll(set._inner, account);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, address account, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, account, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set, address account) internal view returns (uint256) {
        return _length(set._inner, account);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, address account, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, account, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set, address account) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner, account);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address account, address value) internal returns (bool) {
        return _add(set._inner, account, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address account, address value) internal returns (bool) {
        return _remove(set._inner, account, bytes32(uint256(uint160(value))));
    }

    function removeAll(AddressSet storage set, address account) internal {
        return _removeAll(set._inner, account);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address account, address value) internal view returns (bool) {
        return _contains(set._inner, account, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set, address account) internal view returns (uint256) {
        return _length(set._inner, account);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, address account, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, account, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set, address account) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner, account);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, address account, uint256 value) internal returns (bool) {
        return _add(set._inner, account, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, address account, uint256 value) internal returns (bool) {
        return _remove(set._inner, account, bytes32(value));
    }

    function removeAll(UintSet storage set, address account) internal {
        return _removeAll(set._inner, account);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, address account, uint256 value) internal view returns (bool) {
        return _contains(set._inner, account, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set, address account) internal view returns (uint256) {
        return _length(set._inner, account);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, address account, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, account, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set, address account) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner, account);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

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

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

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

interface IERC5267 {
    function eip712Domain() external view returns (
        bytes1 fields,
        string memory name,
        string memory version,
        uint256 chainId,
        address verifyingContract,
        bytes32 salt,
        uint256[] memory extensions
    );
}

/// @title ERC-7739: Nested Typed Data Sign Support for ERC-7579 Validators
abstract contract ERC7739Validator {
    error InvalidSignature();
    
    /// @dev `keccak256("PersonalSign(bytes prefixed)")`.
    bytes32 internal constant _PERSONAL_SIGN_TYPEHASH = 0x983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de;
    bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
    bytes4 internal constant SUPPORTS_ERC7739_V1 = 0x77390001;

    /*//////////////////////////////////////////////////////////////////////////
                                     INTERNAL
    //////////////////////////////////////////////////////////////////////////*/

    /// @dev Returns whether the `signature` is valid for the `hash.
    /// Use this in your validator's `isValidSignatureWithSender` implementation.
    function _erc1271IsValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature)
        internal
        view
        virtual
        returns (bytes4)
    {   
        // detection request
        // this check only takes 17 gas units
        // in theory, it can be moved out of this function so it doesn't apply to every
        // isValidSignatureWithSender() call, but it would require an additional standard
        // interface for SA to check if the IValidator supports ERC-7739
        // while isValidSignatureWithSender() is specified by ERC-7579, so
        // it makes sense to use it in SA to check if the validator supports ERC-7739
        unchecked {
            if (signature.length == uint256(0)) {
                // Forces the compiler to optimize for smaller bytecode size.
                if (uint256(hash) == ~signature.length / 0xffff * 0x7739) 
                    return SUPPORTS_ERC7739_V1;
            }
        }

        // sig malleability prevention
        bytes32 s;
        assembly {
            // same as `s := mload(add(signature, 0x40))` but for calldata
            s := calldataload(add(signature.offset, 0x20))
        }
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            revert InvalidSignature();
        }

        bool success = _erc1271IsValidSignatureViaSafeCaller(sender, hash, signature)
            || _erc1271IsValidSignatureViaNestedEIP712(hash, signature)
            || _erc1271IsValidSignatureViaRPC(hash, signature);

        bytes4 sigValidationResult;
        assembly {
            // `success ? bytes4(keccak256("isValidSignature(bytes32,bytes)")) : 0xffffffff`.
            // We use `0xffffffff` for invalid, in convention with the reference implementation.
            sigValidationResult := shl(224, or(0x1626ba7e, sub(0, iszero(success))))
        }
        return sigValidationResult;
    }

    /// @dev Returns whether the `msg.sender` is considered safe, such
    /// that we don't need to use the nested EIP-712 workflow.
    /// Override to return true for more callers.
    /// See: https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU
    function _erc1271CallerIsSafe(address sender) internal view virtual returns (bool) {
        // The canonical `MulticallerWithSigner` at 0x000000000000D9ECebf3C23529de49815Dac1c4c
        // is known to include the account in the hash to be signed.
        return sender == 0x000000000000D9ECebf3C23529de49815Dac1c4c;
    }

    /// @dev Returns whether the `hash` and `signature` are valid.
    ///      Obtains the authorized signer's credentials and calls some
    ///      module's specific internal function to validate the signature
    ///      against credentials.
    /// Override for your module's custom logic.
    function _erc1271IsValidSignatureNowCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        virtual
        returns (bool);

    /// @dev Unwraps and returns the signature.
    function _erc1271UnwrapSignature(bytes calldata signature)
        internal
        view
        virtual
        returns (bytes calldata result)
    {
        result = signature;
        /// @solidity memory-safe-assembly
        assembly {
            // Unwraps the ERC6492 wrapper if it exists.
            // See: https://eips.ethereum.org/EIPS/eip-6492
            if eq(
                calldataload(add(result.offset, sub(result.length, 0x20))),
                mul(0x6492, div(not(shr(address(), address())), 0xffff)) // `0x6492...6492`.
            ) {
                let o := add(result.offset, calldataload(add(result.offset, 0x40)))
                result.length := calldataload(o)
                result.offset := add(o, 0x20)
            }
        }
    }

    /// @dev Performs the signature validation without nested EIP-712 if the caller is
    /// a safe caller. A safe caller must include the address of this account in the hash.
    function _erc1271IsValidSignatureViaSafeCaller(address sender, bytes32 hash, bytes calldata signature)
        internal
        view
        virtual
        returns (bool result)
    {
        if (_erc1271CallerIsSafe(sender)) result = _erc1271IsValidSignatureNowCalldata(hash, signature);
    }

    /// @dev ERC1271 signature validation (Nested EIP-712 workflow).
    ///
    /// This uses ECDSA recovery by default (see: `_erc1271IsValidSignatureNowCalldata`).
    /// It also uses a nested EIP-712 approach to prevent signature replays when a single EOA
    /// owns multiple smart contract accounts,
    /// while still enabling wallet UIs (e.g. Metamask) to show the EIP-712 values.
    ///
    /// Crafted for phishing resistance, efficiency, flexibility.
    /// __________________________________________________________________________________________
    ///
    /// Glossary:
    ///
    /// - `APP_DOMAIN_SEPARATOR`: The domain separator of the `hash` passed in by the application.
    ///   Provided by the front end. Intended to be the domain separator of the contract
    ///   that will call `isValidSignature` on this account.
    ///
    /// - `ACCOUNT_DOMAIN_SEPARATOR`: The domain separator of this account.
    ///   See: `EIP712._domainSeparator()`.
    /// __________________________________________________________________________________________
    ///
    /// For the `TypedDataSign` workflow, the final hash will be:
    /// ```
    ///     keccak256(\x19\x01 ‖ APP_DOMAIN_SEPARATOR ‖
    ///         hashStruct(TypedDataSign({
    ///             contents: hashStruct(originalStruct),
    ///             name: keccak256(bytes(eip712Domain().name)),
    ///             version: keccak256(bytes(eip712Domain().version)),
    ///             chainId: eip712Domain().chainId,
    ///             verifyingContract: eip712Domain().verifyingContract,
    ///             salt: eip712Domain().salt
    ///         }))
    ///     )
    /// ```
    /// where `‖` denotes the concatenation operator for bytes.
    /// The order of the fields is important: `contents` comes before `name`.
    ///
    /// The signature will be `r ‖ s ‖ v ‖ APP_DOMAIN_SEPARATOR ‖
    ///     contents ‖ contentsDescription ‖ uint16(contentsDescription.length)`,
    /// where:
    /// - `contents` is the bytes32 struct hash of the original struct.
    /// - `contentsDescription` can be either:
    ///     a) `contentsType` (implicit mode)
    ///         where `contentsType` starts with `contentsName`.
    ///     b) `contentsType ‖ contentsName` (explicit mode)
    ///         where `contentsType` may not necessarily start with `contentsName`.
    ///
    /// The `APP_DOMAIN_SEPARATOR` and `contents` will be used to verify if `hash` is indeed correct.
    /// __________________________________________________________________________________________
    ///
    /// For the `PersonalSign` workflow, the final hash will be:
    /// ```
    ///     keccak256(\x19\x01 ‖ ACCOUNT_DOMAIN_SEPARATOR ‖
    ///         hashStruct(PersonalSign({
    ///             prefixed: keccak256(bytes(\x19Ethereum Signed Message:\n ‖
    ///                 base10(bytes(someString).length) ‖ someString))
    ///         }))
    ///     )
    /// ```
    /// where `‖` denotes the concatenation operator for bytes.
    ///
    /// The `PersonalSign` type hash will be `keccak256("PersonalSign(bytes prefixed)")`.
    /// The signature will be `r ‖ s ‖ v`.
    /// __________________________________________________________________________________________
    ///
    /// For demo and typescript code, see:
    /// - https://github.com/junomonster/nested-eip-712
    /// - https://github.com/frangio/eip712-wrapper-for-eip1271
    ///
    /// Their nomenclature may differ from ours, although the high-level idea is similar.
    ///
    /// Of course, if you have control over the codebase of the wallet client(s) too,
    /// you can choose a more minimalistic signature scheme like
    /// `keccak256(abi.encode(address(this), hash))` instead of all these acrobatics.
    /// All these are just for widespread out-of-the-box compatibility with other wallet clients.
    /// We want to create bazaars, not walled castles.
    /// And we'll use push the Turing Completeness of the EVM to the limits to do so.
    function _erc1271IsValidSignatureViaNestedEIP712(bytes32 hash, bytes calldata signature)
        internal
        view
        virtual
        returns (bool result)
    {
        //bytes32 t = _typedDataSignFieldsForAccount(msg.sender);
        uint256 t = uint256(uint160(address(this)));
        // Forces the compiler to pop the variables after the scope, avoiding stack-too-deep.
        if (t != uint256(0)) {
            (
                ,
                string memory name,
                string memory version,
                uint256 chainId,
                address verifyingContract,
                bytes32 salt,
            ) = IERC5267(msg.sender).eip712Domain();
            /// @solidity memory-safe-assembly
            assembly {
                t := mload(0x40) // Grab the free memory pointer.
                // Skip 2 words for the `typedDataSignTypehash` and `contents` struct hash.
                mstore(add(t, 0x40), keccak256(add(name, 0x20), mload(name)))
                mstore(add(t, 0x60), keccak256(add(version, 0x20), mload(version)))
                mstore(add(t, 0x80), chainId)
                mstore(add(t, 0xa0), shr(96, shl(96, verifyingContract)))
                mstore(add(t, 0xc0), salt)
                mstore(0x40, add(t, 0xe0)) // Allocate the memory.
            }
        }

        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            // `c` is `contentsDescription.length`, which is stored in the last 2 bytes of the signature.
            let c := shr(240, calldataload(add(signature.offset, sub(signature.length, 2))))
            for {} 1 {} {
                let l := add(0x42, c) // Total length of appended data (32 + 32 + c + 2).
                let o := add(signature.offset, sub(signature.length, l)) // Offset of appended data.
                mstore(0x00, 0x1901) // Store the "\x19\x01" prefix.
                calldatacopy(0x20, o, 0x40) // Copy the `APP_DOMAIN_SEPARATOR` and `contents` struct hash.
                // Use the `PersonalSign` workflow if the reconstructed hash doesn't match,
                // or if the appended data is invalid, i.e.
                // `appendedData.length > signature.length || contentsDescription.length == 0`.
                if or(xor(keccak256(0x1e, 0x42), hash), or(lt(signature.length, l), iszero(c))) {
                    t := 0 // Set `t` to 0, denoting that we need to `hash = _hashTypedData(hash)`.
                    mstore(t, _PERSONAL_SIGN_TYPEHASH)
                    mstore(0x20, hash) // Store the `prefixed`.
                    hash := keccak256(t, 0x40) // Compute the `PersonalSign` struct hash.
                    break
                }
                // Else, use the `TypedDataSign` workflow.
                // `TypedDataSign({ContentsName} contents,string name,...){ContentsType}`.
                mstore(m, "TypedDataSign(") // Store the start of `TypedDataSign`'s type encoding.
                let p := add(m, 0x0e) // Advance 14 bytes to skip "TypedDataSign(".
                
                calldatacopy(p, add(o, 0x40), c) // Copy `contentsName`, optimistically.
                mstore(add(p, c), 40) // Store a '(' after the end.
                if iszero(eq(byte(0, mload(sub(add(p, c), 1))), 41)) {
                    let e := 0 // Length of `contentsName` in explicit mode.
                    for { let q := sub(add(p, c), 1) } 1 {} {
                        e := add(e, 1) // Scan backwards until we encounter a ')'.
                        if iszero(gt(lt(e, c), eq(byte(0, mload(sub(q, e))), 41))) { break }
                    }
                    c := sub(c, e) // Truncate `contentsDescription` to `contentsType`.
                    calldatacopy(p, add(add(o, 0x40), c), e) // Copy `contentsName`.
                    mstore8(add(p, e), 40) // Store a '(' exactly right after the end.
                }

                // `d & 1 == 1` means that `contentsName` is invalid.
                let d := shr(byte(0, mload(p)), 0x7fffffe000000000000010000000000) // Starts with `[a-z(]`.
                // Advance `p` until we encounter '('.
                for {} iszero(eq(byte(0, mload(p)), 40)) { p := add(p, 1) } {
                    d := or(shr(byte(0, mload(p)), 0x120100000001), d) // Has a byte in ", )\x00".
                }
                mstore(p, " contents,string name,string") // Store the rest of the encoding.
                mstore(add(p, 0x1c), " version,uint256 chainId,address")
                mstore(add(p, 0x3c), " verifyingContract,bytes32 salt)")
                p := add(p, 0x5c)
                calldatacopy(p, add(o, 0x40), c) // Copy `contentsType`.
                // Fill in the missing fields of the `TypedDataSign`.
                calldatacopy(t, o, 0x40) // Copy the `contents` struct hash to `add(t, 0x20)`.
                mstore(t, keccak256(m, sub(add(p, c), m))) // Store `typedDataSignTypehash`.
                // The "\x19\x01" prefix is already at 0x00.
                // `APP_DOMAIN_SEPARATOR` is already at 0x20.
                mstore(0x40, keccak256(t, 0xe0)) // `hashStruct(typedDataSign)`.
                // Compute the final hash, corrupted if `contentsName` is invalid.
                hash := keccak256(0x1e, add(0x42, and(1, d)))
                signature.length := sub(signature.length, l) // Truncate the signature.
                break
            }
            mstore(0x40, m) // Restore the free memory pointer.
        }
        if (t == uint256(0)) hash = _hashTypedDataForAccount(msg.sender, hash); // `PersonalSign` workflow.
        result = _erc1271IsValidSignatureNowCalldata(hash, signature);
    }

    /// @dev Performs the signature validation without nested EIP-712 to allow for easy sign ins.
    /// This function must always return false or revert if called on-chain.
    function _erc1271IsValidSignatureViaRPC(bytes32 hash, bytes calldata signature)
        internal
        view
        virtual
        returns (bool result)
    {
        // Non-zero gasprice is a heuristic to check if a call is on-chain,
        // but we can't fully depend on it because it can be manipulated.
        // See: https://x.com/NoahCitron/status/1580359718341484544
        if (tx.gasprice == uint256(0)) {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(gasprice(), gasprice())
                // See: https://gist.github.com/Vectorized/3c9b63524d57492b265454f62d895f71
                let b := 0x000000000000378eDCD5B5B0A24f5342d8C10485 // Basefee contract,
                pop(staticcall(0xffff, b, codesize(), gasprice(), gasprice(), 0x20))
                // If `gasprice < basefee`, the call cannot be on-chain, and we can skip the gas burn.
                if iszero(mload(gasprice())) {
                    let m := mload(0x40) // Cache the free memory pointer.
                    mstore(gasprice(), 0x1626ba7e) // `isValidSignature(bytes32,bytes)`.
                    mstore(0x20, b) // Recycle `b` to denote if we need to burn gas.
                    mstore(0x40, 0x40)
                    let gasToBurn := or(add(0xffff, gaslimit()), gaslimit())
                    // Burns gas computationally efficiently. Also, requires that `gas > gasToBurn`.
                    if or(eq(hash, b), lt(gas(), gasToBurn)) { invalid() }
                    // Make a call to this with `b`, efficiently burning the gas provided.
                    // No valid transaction can consume more than the gaslimit.
                    // See: https://ethereum.github.io/yellowpaper/paper.pdf
                    // Most RPCs perform calls with a gas budget greater than the gaslimit.
                    pop(staticcall(gasToBurn, address(), 0x1c, 0x64, gasprice(), gasprice()))
                    mstore(0x40, m) // Restore the free memory pointer.
                }
            }
            result = _erc1271IsValidSignatureNowCalldata(hash, signature);
        }
    }

    /// @notice Hashes typed data according to eip-712
    ///         Uses account's domain separator
    /// @param account the smart account, who's domain separator will be used
    /// @param structHash the typed data struct hash
    function _hashTypedDataForAccount(address account, bytes32 structHash) private view returns (bytes32 digest) {
        (
            /*bytes1 fields*/,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            /*bytes32 salt*/,
            /*uint256[] memory extensions*/
        ) = IERC5267(account).eip712Domain();

        /// @solidity memory-safe-assembly
        assembly {
            //Rebuild domain separator out of 712 domain
            let m := mload(0x40) // Load the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), keccak256(add(name, 0x20), mload(name))) // Name hash.
            mstore(add(m, 0x40), keccak256(add(version, 0x20), mload(version))) // Version hash.
            mstore(add(m, 0x60), chainId)
            mstore(add(m, 0x80), verifyingContract)
            digest := keccak256(m, 0xa0) //domain separator

            // Hash typed data
            mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
            mstore(0x1a, digest) // Store the domain separator.
            mstore(0x3a, structHash) // Store the struct hash.
            digest := keccak256(0x18, 0x42)
            // Restore the part of the free memory slot that was overwritten.
            mstore(0x3a, 0)
        }
    }

    /// @dev Backwards compatibility stuff
    /// For automatic detection that the smart account supports the nested EIP-712 workflow.
    /// By default, it returns `bytes32(bytes4(keccak256("supportsNestedTypedDataSign()")))`,
    /// denoting support for the default behavior, as implemented in
    /// `_erc1271IsValidSignatureViaNestedEIP712`, which is called in `isValidSignature`.
    /// Future extensions should return a different non-zero `result` to denote different behavior.
    /// This method intentionally returns bytes32 to allow freedom for future extensions.
    function supportsNestedTypedDataSign() public view virtual returns (bytes32 result) {
        result = bytes4(0xd620c85a);
    }

}

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

bytes3 constant SIG_TYPE_MEE_FLOW = 0x177eee;

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

bytes4 constant EIP1271_SUCCESS = 0x1626ba7e;
bytes4 constant EIP1271_FAILED = 0xffffffff;

uint256 constant MODULE_TYPE_STATELESS_VALIDATOR = 7;

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

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

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

import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
import {EcdsaLib} from "../util/EcdsaLib.sol";
import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
import {IERC20Permit} from "openzeppelin/token/ERC20/extensions/IERC20Permit.sol";
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import "account-abstraction/core/Helpers.sol";

/**
 * @dev Library to validate the signature for MEE ERC-2612 Permit mode
 *      This is the mode where superTx hash is pasted into deadline field of the ERC-2612 Permit
 *      So the whole permit is signed along with the superTx hash
 *      For more details see Fusion docs:
 *      - https://ethresear.ch/t/fusion-module-7702-alternative-with-no-protocol-changes/20949
 *      - https://docs.biconomy.io/explained/eoa#fusion-module
 *
 *      @dev Important: since ERC20 permit token knows nothing about the MEE, it will treat the superTx hash as a deadline:
 *      -  if (very unlikely) the superTx hash being converted to uint256 is a timestamp in the past, the permit will fail
 *      -  the deadline with most superTx hashes will be very far in the future
 *
 *      @dev Since at this point bytes32 superTx hash is a blind hash, users and wallets should pay attention if
 *           the permit2 deadline field does not make sense as the timestamp. In this case, it can be a sign of a
 *           phishing attempt (injecting super txn hash as the deadline) and the user should not sign the permit.
 *           This is going to be mitigated in the future by making superTx hash a EIP-712 hash.
 */
bytes32 constant PERMIT_TYPEHASH =
    keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

struct DecodedErc20PermitSig {
    IERC20Permit token;
    address spender;
    bytes32 domainSeparator;
    uint256 amount;
    uint256 nonce;
    bool isPermitTx;
    bytes32 superTxHash;
    uint48 lowerBoundTimestamp;
    uint48 upperBoundTimestamp;
    uint8 v;
    bytes32 r;
    bytes32 s;
    bytes32[] proof;
}

struct DecodedErc20PermitSigShort {
    address spender;
    bytes32 domainSeparator;
    uint256 amount;
    uint256 nonce;
    bytes32 superTxHash;
    uint8 v;
    bytes32 r;
    bytes32 s;
    bytes32[] proof;
}

library PermitValidatorLib {
    error PermitFailed();

    uint8 constant EIP_155_MIN_V_VALUE = 37;

    using MessageHashUtils for bytes32;

    /**
     * This function parses the given userOpSignature into a DecodedErc20PermitSig data structure.
     *
     * Once parsed, the function will check for two conditions:
     *      1. is the userOp part of the merkle tree
     *      2. is the recovered message signer equal to the expected signer?
     *
     * NOTES: This function will revert if either of following is met:
     *    1. the userOpSignature couldn't be abi.decoded into a valid DecodedErc20PermitSig struct as defined in this contract
     *    2. userOp is not part of the merkle tree
     *    3. recovered Permit message signer wasn't equal to the expected signer
     *
     * The function will also perform the Permit approval on the given token in case the
     * isPermitTx flag was set to true in the decoded signature struct.
     *
     * @param userOpHash UserOp hash being validated.
     * @param parsedSignature Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
     * @param expectedSigner Signer expected to be recovered when decoding the ERC20OPermit signature.
     */
    function validateUserOp(bytes32 userOpHash, bytes calldata parsedSignature, address expectedSigner)
        internal
        returns (uint256)
    {
        DecodedErc20PermitSig memory decodedSig = _decodeFullPermitSig(parsedSignature);

        bytes32 meeUserOpHash = MEEUserOpHashLib.getMEEUserOpHash(
            userOpHash, decodedSig.lowerBoundTimestamp, decodedSig.upperBoundTimestamp
        );

        if (
            !EcdsaLib.isValidSignature(
                expectedSigner,
                _getSignedDataHash(expectedSigner, decodedSig),
                abi.encodePacked(decodedSig.r, decodedSig.s, uint8(decodedSig.v))
            )
        ) {
            return SIG_VALIDATION_FAILED;
        }

        if (!MerkleProof.verify(decodedSig.proof, decodedSig.superTxHash, meeUserOpHash)) {
            return SIG_VALIDATION_FAILED;
        }

        if (decodedSig.isPermitTx) {
            try decodedSig.token.permit(
                expectedSigner,
                decodedSig.spender,
                decodedSig.amount,
                uint256(decodedSig.superTxHash),
                uint8(decodedSig.v),
                decodedSig.r,
                decodedSig.s
            ) {
                // all good
            } catch {
                // check if by some reason this permit was already successfully used (and not spent yet)
                if (IERC20(address(decodedSig.token)).allowance(expectedSigner, decodedSig.spender) < decodedSig.amount)
                {
                    // if the above expectationis not true, revert
                    revert PermitFailed();
                }
            }
        }

        return _packValidationData(false, decodedSig.upperBoundTimestamp, decodedSig.lowerBoundTimestamp);
    }

    function validateSignatureForOwner(address expectedSigner, bytes32 dataHash, bytes calldata parsedSignature)
        internal
        view
        returns (bool)
    {
        DecodedErc20PermitSigShort calldata decodedSig = _decodeShortPermitSig(parsedSignature);

        if (
            !EcdsaLib.isValidSignature(
                expectedSigner,
                _getSignedDataHash(expectedSigner, decodedSig),
                abi.encodePacked(decodedSig.r, decodedSig.s, uint8(decodedSig.v))
            )
        ) {
            return false;
        }

        if (!MerkleProof.verify(decodedSig.proof, decodedSig.superTxHash, dataHash)) {
            return false;
        }

        return true;
    }

    function _decodeFullPermitSig(bytes calldata parsedSignature)
        private
        pure
        returns (DecodedErc20PermitSig calldata decodedSig)
    {
        assembly {
            decodedSig := add(parsedSignature.offset, 0x20)
        }
    }

    function _decodeShortPermitSig(bytes calldata parsedSignature)
        private
        pure
        returns (DecodedErc20PermitSigShort calldata)
    {
        DecodedErc20PermitSigShort calldata decodedSig;
        assembly {
            decodedSig := add(parsedSignature.offset, 0x20)
        }
        return decodedSig;
    }

    function _getSignedDataHash(address expectedSigner, DecodedErc20PermitSig memory decodedSig)
        private
        pure
        returns (bytes32)
    {
        uint256 deadline = uint256(decodedSig.superTxHash);

        bytes32 structHash = keccak256(
            abi.encode(
                PERMIT_TYPEHASH, expectedSigner, decodedSig.spender, decodedSig.amount, decodedSig.nonce, deadline
            )
        );
        return _hashTypedData(structHash, decodedSig.domainSeparator);
    }

    function _getSignedDataHash(address expectedSigner, DecodedErc20PermitSigShort memory decodedSig)
        private
        pure
        returns (bytes32)
    {
        uint256 deadline = uint256(decodedSig.superTxHash);

        bytes32 structHash = keccak256(
            abi.encode(
                PERMIT_TYPEHASH, expectedSigner, decodedSig.spender, decodedSig.amount, decodedSig.nonce, deadline
            )
        );
        return _hashTypedData(structHash, decodedSig.domainSeparator);
    }

    function _hashTypedData(bytes32 structHash, bytes32 domainSeparator) private pure returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(domainSeparator, structHash);
    }
}

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

import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
import {RLPReader as RLPDecoder} from "rlp-reader/RLPReader.sol";
import {RLPEncoder} from "../rlp/RLPEncoder.sol";
import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
import {EcdsaLib} from "../util/EcdsaLib.sol";
import {BytesLib} from "byteslib/BytesLib.sol";
import "account-abstraction/core/Helpers.sol";

/**
 * @dev Library to validate the signature for MEE on-chain Txn mode
 *      This is the mode where superTx hash is appended to a regular txn (legacy or 1559) calldata
 *      Type 1 (EIP-2930) transactions are not supported.
 *      The whole txn is signed along with the superTx hash
 *      Txn is executed prior to a superTx, so it can pass some funds from the EOA to the smart account
 *      For more details see Fusion docs:
 *      - https://ethresear.ch/t/fusion-module-7702-alternative-with-no-protocol-changes/20949
 *      - https://docs.biconomy.io/explained/eoa#fusion-module
 *      @dev Some smart contracts may not be able to consume the txn with bytes32 appended to the calldata.
 *           However this is very small subset. One of the cases when it can happen is when the smart contract
 *           is has separate receive() and fallback() functions. Then if a txn is a value transfer, it will
 *           be expected to be consumed by the receive() function. However, if there's bytes32 appended to the calldata,
 *           it will be consumed by the fallback() function which may not be expected. In this case, the provided
 *           contracts/forwarder/Forwarder.sol can be used to 'clear' the bytes32 from the calldata.
 *      @dev In theory, the last 32 bytes of calldata from any transaction by the EOA can be interpreted as
 *           a superTx hash. Even if it was not assumed. This introduces the potential risk of phishing attacks
 *           where the user may unknowingly sign a transaction where the last 32 bytes of the calldata end up
 *           being a superTx hash. However, it is not easy to craft a txn that makes sense for a user and allows
 *           arbitrary bytes32 as last 32 bytes. Thus, wallets and users should be aware of this potential risk
 *           and should not sign txns where the last 32 bytes of the calldata do not belong to the function arguments
 *           and are just appended at the end.
 */
library TxValidatorLib {
    uint8 constant LEGACY_TX_TYPE = 0x00;
    uint8 constant EIP1559_TX_TYPE = 0x02;

    uint8 constant EIP_155_MIN_V_VALUE = 37;
    uint8 constant HASH_BYTE_SIZE = 32;

    uint8 constant TIMESTAMP_BYTE_SIZE = 6;
    uint8 constant PROOF_ITEM_BYTE_SIZE = 32;
    uint8 constant ITX_HASH_BYTE_SIZE = 32;

    using RLPDecoder for RLPDecoder.RLPItem;
    using RLPDecoder for bytes;
    using RLPEncoder for uint256;
    using BytesLib for bytes;

    struct TxData {
        uint8 txType;
        uint8 v;
        bytes32 r;
        bytes32 s;
        bytes32 utxHash;
        bytes32 superTxHash;
        bytes32[] proof;
        uint48 lowerBoundTimestamp;
        uint48 upperBoundTimestamp;
    }

    // To save a bit of gas, not pass timestamps where not needed
    struct TxDataShort {
        uint8 txType;
        uint8 v;
        bytes32 r;
        bytes32 s;
        bytes32 utxHash;
        bytes32 superTxHash;
        bytes32[] proof;
    }

    struct TxParams {
        uint256 v;
        bytes32 r;
        bytes32 s;
        bytes callData;
    }

    /**
     * This function parses the given userOpSignature into a valid fully signed EVM transaction.
     * Once parsed, the function will check for three conditions:
     *      1. is the userOp part of the superTX merkle tree
     *      2. is the recovered tx signer equal to the expected signer?
     *      3. is the given UserOp a part of the merkle tree
     *
     * If all the conditions are met - outside contract can be sure that the expected signer has indeed
     * approved the given hash by performing given on-chain transaction.
     *
     * NOTES: This function will revert if either of following is met:
     *    1. the userOpSignature couldn't be parsed to a valid fully signed EVM transaction
     *    2. hash couldn't be extracted from the tx.data
     *    3. extracted hash wasn't equal to the provided expected hash
     *    4. recovered signer wasn't equal to the expected signer
     *
     * @param userOpHash UserOp hash being validated.
     * @param parsedSignature Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
     *                        Expecting to receive fully signed serialized EVM transaction here of type 0x00 (LEGACY)
     *                        or 0x02 (EIP1556).
     *                        For LEGACY tx type the "0x00" prefix has to be added manually while the EIP1559 tx type
     *                        already contains 0x02 prefix.
     * @param expectedSigner Expected EOA signer of the given EVM transaction => superTX.
     */
    function validateUserOp(bytes32 userOpHash, bytes calldata parsedSignature, address expectedSigner)
        internal
        view
        returns (uint256)
    {
        TxData memory decodedTx = decodeTx(parsedSignature);

        bytes32 meeUserOpHash =
            MEEUserOpHashLib.getMEEUserOpHash(userOpHash, decodedTx.lowerBoundTimestamp, decodedTx.upperBoundTimestamp);

        bytes memory signature = abi.encodePacked(decodedTx.r, decodedTx.s, decodedTx.v);
        if (!EcdsaLib.isValidSignature(expectedSigner, decodedTx.utxHash, signature)) {
            return SIG_VALIDATION_FAILED;
        }

        if (!MerkleProof.verify(decodedTx.proof, decodedTx.superTxHash, meeUserOpHash)) {
            return SIG_VALIDATION_FAILED;
        }

        return _packValidationData(false, decodedTx.upperBoundTimestamp, decodedTx.lowerBoundTimestamp);
    }

    /**
     * @dev validate the signature for the owner of the superTx
     *      used fot the 1271 flow and for the stateless validators (erc7579 module type 7)
     * @param expectedSigner the expected signer of the superTx
     * @param dataHash the hash of the data to be signed
     * @param parsedSignature the signature to be validated
     * @return true if the signature is valid, false otherwise
     */
    function validateSignatureForOwner(address expectedSigner, bytes32 dataHash, bytes calldata parsedSignature)
        internal
        view
        returns (bool)
    {
        TxDataShort memory decodedTx = decodeTxShort(parsedSignature);

        bytes memory signature = abi.encodePacked(decodedTx.r, decodedTx.s, decodedTx.v);

        if (!EcdsaLib.isValidSignature(expectedSigner, decodedTx.utxHash, signature)) {
            return false;
        }

        if (!MerkleProof.verify(decodedTx.proof, decodedTx.superTxHash, dataHash)) {
            return false;
        }
        return true;
    }

    function decodeTx(bytes calldata self) internal pure returns (TxData memory) {
        uint8 txType = uint8(self[0]); //first byte is tx type
        uint48 lowerBoundTimestamp =
            uint48(bytes6((self[self.length - 2 * TIMESTAMP_BYTE_SIZE:self.length - TIMESTAMP_BYTE_SIZE])));
        uint48 upperBoundTimestamp = uint48(bytes6(self[self.length - TIMESTAMP_BYTE_SIZE:]));
        uint8 proofItemsCount = uint8(self[self.length - 2 * TIMESTAMP_BYTE_SIZE - 1]);
        uint256 appendedDataLen = (uint256(proofItemsCount) * PROOF_ITEM_BYTE_SIZE + 1) + 2 * TIMESTAMP_BYTE_SIZE;
        bytes calldata rlpEncodedTx = self[1:self.length - appendedDataLen];
        RLPDecoder.RLPItem memory parsedRlpEncodedTx = rlpEncodedTx.toRlpItem();
        RLPDecoder.RLPItem[] memory parsedRlpEncodedTxItems = parsedRlpEncodedTx.toList();
        TxParams memory params = extractParams(txType, parsedRlpEncodedTxItems);

        return TxData({
            txType: txType,
            v: _adjustV(params.v),
            r: params.r,
            s: params.s,
            utxHash: calculateUnsignedTxHash(txType, rlpEncodedTx, parsedRlpEncodedTx.payloadLen(), params.v, params.r, params.s),
            superTxHash: extractAppendedHash(params.callData),
            proof: extractProof(self, proofItemsCount),
            lowerBoundTimestamp: lowerBoundTimestamp,
            upperBoundTimestamp: upperBoundTimestamp
        });
    }

    function decodeTxShort(bytes calldata self) internal pure returns (TxDataShort memory) {
        uint8 txType = uint8(self[0]); //first byte is tx type
        uint8 proofItemsCount = uint8(self[self.length - 1]);
        uint256 appendedDataLen = (uint256(proofItemsCount) * PROOF_ITEM_BYTE_SIZE + 1);
        bytes calldata rlpEncodedTx = self[1:self.length - appendedDataLen];
        RLPDecoder.RLPItem memory parsedRlpEncodedTx = rlpEncodedTx.toRlpItem();
        RLPDecoder.RLPItem[] memory parsedRlpEncodedTxItems = parsedRlpEncodedTx.toList();
        TxParams memory params = extractParams(txType, parsedRlpEncodedTxItems);

        return TxDataShort({
            txType: txType,
            v: _adjustV(params.v),
            r: params.r,
            s: params.s,
            utxHash: calculateUnsignedTxHash(txType, rlpEncodedTx, parsedRlpEncodedTx.payloadLen(), params.v, params.r, params.s),
            superTxHash: extractAppendedHash(params.callData),
            proof: extractProofShort(self, proofItemsCount)
        });
    }

    function extractParams(uint8 txType, RLPDecoder.RLPItem[] memory items)
        private
        pure
        returns (TxParams memory params)
    {
        uint8 dataPos;
        uint8 vPos;
        uint8 rPos;
        uint8 sPos;

        if (txType == LEGACY_TX_TYPE) {
            dataPos = 5;
            vPos = 6;
            rPos = 7;
            sPos = 8;
        } else if (txType == EIP1559_TX_TYPE) {
            dataPos = 7;
            vPos = 9;
            rPos = 10;
            sPos = 11;
        } else {
            revert("TxValidatorLib:: unsupported evm tx type");
        }

        return TxParams(
            items[vPos].toUint(), bytes32(items[rPos].toUint()), bytes32(items[sPos].toUint()), items[dataPos].toBytes()
        );
    }

    function extractAppendedHash(bytes memory callData) private pure returns (bytes32 iTxHash) {
        if (callData.length < ITX_HASH_BYTE_SIZE) revert("TxDecoder:: callData length too short");
        iTxHash = bytes32(callData.slice(callData.length - ITX_HASH_BYTE_SIZE, ITX_HASH_BYTE_SIZE));
    }

    function extractProof(bytes calldata signedTx, uint8 proofItemsCount)
        private
        pure
        returns (bytes32[] memory proof)
    {
        proof = new bytes32[](proofItemsCount);
        uint256 pos = signedTx.length - 2 * TIMESTAMP_BYTE_SIZE - 1;
        for (proofItemsCount; proofItemsCount > 0; proofItemsCount--) {
            proof[proofItemsCount - 1] = bytes32(signedTx[pos - PROOF_ITEM_BYTE_SIZE:pos]);
            pos = pos - PROOF_ITEM_BYTE_SIZE;
        }
    }

    function extractProofShort(bytes calldata signedTx, uint8 proofItemsCount)
        private
        pure
        returns (bytes32[] memory proof)
    {
        proof = new bytes32[](proofItemsCount);
        uint256 pos = signedTx.length - 1;
        for (proofItemsCount; proofItemsCount > 0; proofItemsCount--) {
            proof[proofItemsCount - 1] = bytes32(signedTx[pos - PROOF_ITEM_BYTE_SIZE:pos]);
            pos = pos - PROOF_ITEM_BYTE_SIZE;
        }
    }

    function calculateUnsignedTxHash(
        uint8 txType,
        bytes memory rlpEncodedTx,
        uint256 rlpEncodedTxPayloadLen,
        uint256 v,
        bytes32 r,
        bytes32 s
    ) private pure returns (bytes32 hash) {
        uint256 totalSignatureSize =
            uint256(r).encodeUint().length + uint256(s).encodeUint().length + v.encodeUint().length;
        uint256 totalPrefixSize = rlpEncodedTx.length - rlpEncodedTxPayloadLen;
        bytes memory rlpEncodedTxNoSigAndPrefix =
            rlpEncodedTx.slice(totalPrefixSize, rlpEncodedTx.length - totalSignatureSize - totalPrefixSize);
        if (txType == EIP1559_TX_TYPE) {
            return keccak256(abi.encodePacked(txType, prependRlpContentSize(rlpEncodedTxNoSigAndPrefix, "")));
        } else if (txType == LEGACY_TX_TYPE) {
            if (v >= EIP_155_MIN_V_VALUE) {
                return keccak256(
                    prependRlpContentSize(
                        rlpEncodedTxNoSigAndPrefix,
                        abi.encodePacked(
                            uint256(_extractChainIdFromV(v)).encodeUint(),
                            uint256(0).encodeUint(),
                            uint256(0).encodeUint()
                        )
                    )
                );
            } else {
                return keccak256(prependRlpContentSize(rlpEncodedTxNoSigAndPrefix, ""));
            }
        } else {
            revert("TxValidatorLib:: unsupported tx type");
        }
    }

    function prependRlpContentSize(bytes memory content, bytes memory extraData) public pure returns (bytes memory) {
        bytes memory combinedContent = abi.encodePacked(content, extraData);
        return abi.encodePacked(combinedContent.length.encodeLength(RLPDecoder.LIST_SHORT_START), combinedContent);
    }

    function _adjustV(uint256 v) internal pure returns (uint8) {
        if (v >= EIP_155_MIN_V_VALUE) {
            return uint8((v - 2 * _extractChainIdFromV(v) - 35) + 27);
        } else if (v <= 1) {
            return uint8(v + 27);
        } else {
            return uint8(v);
        }
    }

    function _extractChainIdFromV(uint256 v) internal pure returns (uint256 chainId) {
        chainId = (v - 35) / 2;
    }
}

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

import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
import {EcdsaLib} from "../util/EcdsaLib.sol";
import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
import "account-abstraction/core/Helpers.sol";

/**
 * @dev Library to validate the signature for MEE Simple mode
 *      In this mode, Fusion is not involved and just the superTx hash is signed
 */
library SimpleValidatorLib {
    /**
     * This function parses the given userOpSignature into a Supertransaction signature
     *
     * Once parsed, the function will check for two conditions:
     *      1. is the root supertransaction hash signed by the account owner's EOA
     *      2. is the userOp actually a part of the given supertransaction
     *      by checking the leaf based on this userOpHash is a part of the merkle tree represented by root hash = superTxHash
     *
     * If both conditions are met - outside contract can be sure that the expected signer has indeed
     * approved the given userOp - and the userOp is successfully validate.
     *
     * @param userOpHash UserOp hash being validated.
     * @param signatureData Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
     * @param expectedSigner Signer expected to be recovered when decoding the ERC20OPermit signature.
     */
    function validateUserOp(bytes32 userOpHash, bytes calldata signatureData, address expectedSigner)
        internal
        view
        returns (uint256)
    {
        bytes32 superTxHash;
        uint48 lowerBoundTimestamp;
        uint48 upperBoundTimestamp;
        bytes32[] calldata proof;
        bytes calldata secp256k1Signature;

        assembly {
            superTxHash := calldataload(signatureData.offset)
            lowerBoundTimestamp := calldataload(add(signatureData.offset, 0x20))
            upperBoundTimestamp := calldataload(add(signatureData.offset, 0x40))
            let u := calldataload(add(signatureData.offset, 0x60))
            let s := add(signatureData.offset, u)
            proof.offset := add(s, 0x20)
            proof.length := calldataload(s)
            u := mul(proof.length, 0x20)
            s := add(proof.offset, u)
            secp256k1Signature.offset := add(s, 0x20)
            secp256k1Signature.length := calldataload(s)
        }

        bytes32 leaf = MEEUserOpHashLib.getMEEUserOpHash(userOpHash, lowerBoundTimestamp, upperBoundTimestamp);
        if (!EcdsaLib.isValidSignature(expectedSigner, superTxHash, secp256k1Signature)) {
            return SIG_VALIDATION_FAILED;
        }

        if (!MerkleProof.verify(proof, superTxHash, leaf)) {
            return SIG_VALIDATION_FAILED;
        }

        return _packValidationData(false, upperBoundTimestamp, lowerBoundTimestamp);
    }

    /**
     * @notice Validates the signature against the expected signer (owner)
     * @param owner Signer expected to be recovered
     * @param dataHash data hash being validated.
     * @param signatureData Signature
     */
    function validateSignatureForOwner(address owner, bytes32 dataHash, bytes calldata signatureData)
        internal
        view
        returns (bool)
    {
        bytes32 superTxHash;
        bytes32[] calldata proof;
        bytes calldata secp256k1Signature;

        assembly {
            superTxHash := calldataload(signatureData.offset)
            let u := calldataload(add(signatureData.offset, 0x20))
            let s := add(signatureData.offset, u)
            proof.offset := add(s, 0x20)
            proof.length := calldataload(s)
            u := mul(proof.length, 0x20)
            s := add(proof.offset, u)
            secp256k1Signature.offset := add(s, 0x20)
            secp256k1Signature.length := calldataload(s)
        }

        if (!EcdsaLib.isValidSignature(owner, superTxHash, secp256k1Signature)) {
            return false;
        }

        if (!MerkleProof.verify(proof, superTxHash, dataHash)) {
            return false;
        }

        return true;
    }
}

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

import "account-abstraction/interfaces/PackedUserOperation.sol";
import "account-abstraction/core/Helpers.sol";
import "../util/EcdsaLib.sol";

library NoMeeFlowLib {
    /**
     * Standard userOp validator - validates by simply checking if the userOpHash was signed by the account's EOA owner.
     *
     * @param userOpHash userOpHash being validated.
     * @param parsedSignature Signature
     * @param expectedSigner Signer expected to be recovered
     */
    function validateUserOp(bytes32 userOpHash, bytes memory parsedSignature, address expectedSigner)
        internal
        view
        returns (uint256)
    {
        if (!EcdsaLib.isValidSignature(expectedSigner, userOpHash, parsedSignature)) {
            return SIG_VALIDATION_FAILED;
        }
        return SIG_VALIDATION_SUCCESS;
    }

    /**
     * @notice Validates the signature against the expected signer (owner)
     * @param expectedSigner Signer expected to be recovered
     * @param hash Hash of the userOp
     * @param parsedSignature Signature
     */
    function validateSignatureForOwner(address expectedSigner, bytes32 hash, bytes memory parsedSignature)
        internal
        view
        returns (bool)
    {
        return EcdsaLib.isValidSignature(expectedSigner, hash, parsedSignature);
    }
}

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

import {ECDSA} from "solady/utils/ECDSA.sol";

library EcdsaLib {
    using ECDSA for bytes32;

    /**
     * @dev Solady ECDSA does not revert on incorrect signatures.
     *      Instead, it returns address(0) as the recovered address.
     *      Make sure to never pass address(0) as expectedSigner to this function.
     */
    function isValidSignature(address expectedSigner, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool)
    {
        if (hash.tryRecover(signature) == expectedSigner) return true;
        if (hash.toEthSignedMessageHash().tryRecover(signature) == expectedSigner) return true;
        return false;
    }
}

File 13 of 26 : AssociatedArrayLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * Dynamic arrays associated with an account address as per ERC-7562/ERC-4337
 * @author filio.eth (Biconomy), zeroknots.eth (rhinestone)
 */
library AssociatedArrayLib {
    using AssociatedArrayLib for *;

    error AssociatedArray_OutOfBounds(uint256 index);

    struct Array {
        uint256 _spacer;
    }

    function _slot(Array storage s, address account) private pure returns (bytes32 __slot) {
        assembly {
            mstore(0x00, account)
            mstore(0x20, s.slot)
            __slot := keccak256(0x00, 0x40)
        }
    }

    function _length(Array storage s, address account) private view returns (uint256 __length) {
        bytes32 slot = _slot(s, account);
        assembly {
            __length := sload(slot)
        }
    }

    function _get(Array storage s, address account, uint256 index) private view returns (bytes32 value) {
        return _get(_slot(s, account), index);
    }

    function _get(bytes32 slot, uint256 index) private view returns (bytes32 value) {
        assembly {
            //if (index >= _length(s, account)) revert AssociatedArray_OutOfBounds(index);
            if iszero(lt(index, sload(slot))) {
                mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                mstore(0x20, index)
                revert(0x1c, 0x24)
            }
            value := sload(add(slot, mul(0x20, add(index, 1))))
        }
    }

    function _getAll(Array storage s, address account) private view returns (bytes32[] memory values) {
        bytes32 slot = _slot(s, account);
        uint256 __length;
        assembly {
            __length := sload(slot)
        }
        values = new bytes32[](__length);
        for (uint256 i; i < __length; i++) {
            values[i] = _get(slot, i);
        }
    }

    // inefficient. complexity = O(n)
    // use with caution
    // in case of large arrays, consider using EnumerableSet4337 instead
    function _contains(Array storage s, address account, bytes32 value) private view returns (bool) {
        bytes32 slot = _slot(s, account);
        uint256 __length;
        assembly {
            __length := sload(slot)
        }
        for (uint256 i; i < __length; i++) {
            if (_get(slot, i) == value) {
                return true;
            }
        }
        return false;
    }

    function _set(Array storage s, address account, uint256 index, bytes32 value) private {
        _set(_slot(s, account), index, value);
    }

    function _set(bytes32 slot, uint256 index, bytes32 value) private {
        assembly {
            //if (index >= _length(s, account)) revert AssociatedArray_OutOfBounds(index);
            if iszero(lt(index, sload(slot))) {
                mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                mstore(0x20, index)
                revert(0x1c, 0x24)
            }
            sstore(add(slot, mul(0x20, add(index, 1))), value)
        }
    }

    function _push(Array storage s, address account, bytes32 value) private {
        bytes32 slot = _slot(s, account);
        assembly {
            // load length (stored @ slot), add 1 to it => index.
            // mul index by 0x20 and add it to orig slot to get the next free slot
            let index := add(sload(slot), 1)
            sstore(add(slot, mul(0x20, index)), value)
            sstore(slot, index) //increment length by 1
        }
    }

    function _pop(Array storage s, address account) private {
        bytes32 slot = _slot(s, account);
        uint256 __length;
        assembly {
            __length := sload(slot)
        }
        if (__length == 0) return;
        _set(slot, __length - 1, 0);
        assembly {
            sstore(slot, sub(__length, 1))
        }
    }

    function _remove(Array storage s, address account, uint256 index) private {
        bytes32 slot = _slot(s, account);
        uint256 __length;
        assembly {
            __length := sload(slot)
            if iszero(lt(index, __length)) {
                mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                mstore(0x20, index)
                revert(0x1c, 0x24)
            }
        }
        _set(slot, index, _get(s, account, __length - 1));

        assembly {
            // clear the last slot
            // this is the 'unchecked' version of _set(slot, __length - 1, 0)
            // as we use length-1 as index, so the check is excessive.
            // also removes extra -1 and +1 operations
            sstore(add(slot, mul(0x20, __length)), 0)
            // store new length
            sstore(slot, sub(__length, 1))
        }
    }

    struct Bytes32Array {
        Array _inner;
    }

    function length(Bytes32Array storage s, address account) internal view returns (uint256) {
        return _length(s._inner, account);
    }

    function get(Bytes32Array storage s, address account, uint256 index) internal view returns (bytes32) {
        return _get(s._inner, account, index);
    }

    function getAll(Bytes32Array storage s, address account) internal view returns (bytes32[] memory) {
        return _getAll(s._inner, account);
    }

    function contains(Bytes32Array storage s, address account, bytes32 value) internal view returns (bool) {
        return _contains(s._inner, account, value);
    }

    function add(Bytes32Array storage s, address account, bytes32 value) internal {
        if (!_contains(s._inner, account, value)) {
            _push(s._inner, account, value);
        }
    }

    function set(Bytes32Array storage s, address account, uint256 index, bytes32 value) internal {
        _set(s._inner, account, index, value);
    }

    function push(Bytes32Array storage s, address account, bytes32 value) internal {
        _push(s._inner, account, value);
    }

    function pop(Bytes32Array storage s, address account) internal {
        _pop(s._inner, account);
    }

    function remove(Bytes32Array storage s, address account, uint256 index) internal {
        _remove(s._inner, account, index);
    }

    struct AddressArray {
        Array _inner;
    }

    function length(AddressArray storage s, address account) internal view returns (uint256) {
        return _length(s._inner, account);
    }

    function get(AddressArray storage s, address account, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_get(s._inner, account, index))));
    }

    function getAll(AddressArray storage s, address account) internal view returns (address[] memory) {
        bytes32[] memory bytes32Array = _getAll(s._inner, account);
        address[] memory addressArray;

        /// @solidity memory-safe-assembly
        assembly {
            addressArray := bytes32Array
        }
        return addressArray;
    }

    function contains(AddressArray storage s, address account, address value) internal view returns (bool) {
        return _contains(s._inner, account, bytes32(uint256(uint160(value))));
    }

    function add(AddressArray storage s, address account, address value) internal {
        if (!_contains(s._inner, account, bytes32(uint256(uint160(value))))) {
            _push(s._inner, account, bytes32(uint256(uint160(value))));
        }
    }

    function set(AddressArray storage s, address account, uint256 index, address value) internal {
        _set(s._inner, account, index, bytes32(uint256(uint160(value))));
    }

    function push(AddressArray storage s, address account, address value) internal {
        _push(s._inner, account, bytes32(uint256(uint160(value))));
    }

    function pop(AddressArray storage s, address account) internal {
        _pop(s._inner, account);
    }

    function remove(AddressArray storage s, address account, uint256 index) internal {
        _remove(s._inner, account, index);
    }

    struct UintArray {
        Array _inner;
    }

    function length(UintArray storage s, address account) internal view returns (uint256) {
        return _length(s._inner, account);
    }

    function get(UintArray storage s, address account, uint256 index) internal view returns (uint256) {
        return uint256(_get(s._inner, account, index));
    }

    function getAll(UintArray storage s, address account) internal view returns (uint256[] memory) {
        bytes32[] memory bytes32Array = _getAll(s._inner, account);
        uint256[] memory uintArray;

        /// @solidity memory-safe-assembly
        assembly {
            uintArray := bytes32Array
        }
        return uintArray;
    }

    function contains(UintArray storage s, address account, uint256 value) internal view returns (bool) {
        return _contains(s._inner, account, bytes32(value));
    }

    function add(UintArray storage s, address account, uint256 value) internal {
        if (!_contains(s._inner, account, bytes32(value))) {
            _push(s._inner, account, bytes32(value));
        }
    }

    function set(UintArray storage s, address account, uint256 index, uint256 value) internal {
        _set(s._inner, account, index, bytes32(value));
    }

    function push(UintArray storage s, address account, uint256 value) internal {
        _push(s._inner, account, bytes32(value));
    }

    function pop(UintArray storage s, address account) internal {
        _pop(s._inner, account);
    }

    function remove(UintArray storage s, address account, uint256 index) internal {
        _remove(s._inner, account, index);
    }
}

// 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/cryptography/MerkleProof.sol)

pragma solidity ^0.8.20;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

// SPDX-License-Identifier: Unlicense
/*
 * @title MEE UserOp Hash Lib
 *
 * @dev Calculates userOp hash for the new type of transaction - SuperTransaction (as a part of MEE stack)
 */
pragma solidity ^0.8.27;

library MEEUserOpHashLib {
    /**
     * Calculates userOp hash. Almost works like a regular 4337 userOp hash with few fields added.
     *
     * @param userOpHash userOp hash to calculate the hash for
     * @param lowerBoundTimestamp lower bound timestamp set when constructing userOp
     * @param upperBoundTimestamp upper bound timestamp set when constructing userOp
     * Timestamps are used by the MEE node to schedule the execution of the userOps within the superTx
     */
    function getMEEUserOpHash(bytes32 userOpHash, uint256 lowerBoundTimestamp, uint256 upperBoundTimestamp)
        internal
        pure
        returns (bytes32 meeUserOpHash)
    {
        meeUserOpHash =
            keccak256(bytes.concat(keccak256(abi.encode(userOpHash, lowerBoundTimestamp, upperBoundTimestamp))));
    }
}

// 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) (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: GPL-3.0
pragma solidity ^0.8.23;

/* solhint-disable no-inline-assembly */


 /*
  * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
  * must return this value in case of signature failure, instead of revert.
  */
uint256 constant SIG_VALIDATION_FAILED = 1;


/*
 * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
 * return this value on success.
 */
uint256 constant SIG_VALIDATION_SUCCESS = 0;


/**
 * Returned data from validateUserOp.
 * validateUserOp returns a uint256, which is created by `_packedValidationData` and
 * parsed by `_parseValidationData`.
 * @param aggregator  - address(0) - The account validated the signature by itself.
 *                      address(1) - The account failed to validate the signature.
 *                      otherwise - This is an address of a signature aggregator that must
 *                                  be used to validate the signature.
 * @param validAfter  - This UserOp is valid only after this timestamp.
 * @param validaUntil - This UserOp is valid only up to this timestamp.
 */
struct ValidationData {
    address aggregator;
    uint48 validAfter;
    uint48 validUntil;
}

/**
 * Extract sigFailed, validAfter, validUntil.
 * Also convert zero validUntil to type(uint48).max.
 * @param validationData - The packed validation data.
 */
function _parseValidationData(
    uint256 validationData
) pure returns (ValidationData memory data) {
    address aggregator = address(uint160(validationData));
    uint48 validUntil = uint48(validationData >> 160);
    if (validUntil == 0) {
        validUntil = type(uint48).max;
    }
    uint48 validAfter = uint48(validationData >> (48 + 160));
    return ValidationData(aggregator, validAfter, validUntil);
}

/**
 * Helper to pack the return value for validateUserOp.
 * @param data - The ValidationData to pack.
 */
function _packValidationData(
    ValidationData memory data
) pure returns (uint256) {
    return
        uint160(data.aggregator) |
        (uint256(data.validUntil) << 160) |
        (uint256(data.validAfter) << (160 + 48));
}

/**
 * Helper to pack the return value for validateUserOp, when not using an aggregator.
 * @param sigFailed  - True for signature failure, false for success.
 * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite).
 * @param validAfter - First timestamp this UserOperation is valid.
 */
function _packValidationData(
    bool sigFailed,
    uint48 validUntil,
    uint48 validAfter
) pure returns (uint256) {
    return
        (sigFailed ? 1 : 0) |
        (uint256(validUntil) << 160) |
        (uint256(validAfter) << (160 + 48));
}

/**
 * keccak function over calldata.
 * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
 */
    function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
        assembly ("memory-safe") {
            let mem := mload(0x40)
            let len := data.length
            calldatacopy(mem, data.offset, len)
            ret := keccak256(mem, len)
        }
    }


/**
 * The minimum of two numbers.
 * @param a - First number.
 * @param b - Second number.
 */
    function min(uint256 a, uint256 b) pure returns (uint256) {
        return a < b ? a : b;
    }

// SPDX-License-Identifier: Apache-2.0

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 */
pragma solidity >=0.5.10 <0.9.0;

library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START = 0xb8;
    uint8 constant LIST_SHORT_START = 0xc0;
    uint8 constant LIST_LONG_START = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
        uint256 len;
        uint256 memPtr;
    }

    struct Iterator {
        RLPItem item; // Item that's being iterated over.
        uint256 nextPtr; // Position of the next item in the list.
    }

    /*
     * @dev Returns the next element in the iteration. Reverts if it has not next element.
     * @param self The iterator.
     * @return The next element in the iteration.
     */
    function next(Iterator memory self) internal pure returns (RLPItem memory) {
        require(hasNext(self));

        uint256 ptr = self.nextPtr;
        uint256 itemLength = _itemLength(ptr);
        self.nextPtr = ptr + itemLength;

        return RLPItem(itemLength, ptr);
    }

    /*
     * @dev Returns true if the iteration has more elements.
     * @param self The iterator.
     * @return true if the iteration has more elements.
     */
    function hasNext(Iterator memory self) internal pure returns (bool) {
        RLPItem memory item = self.item;
        return self.nextPtr < item.memPtr + item.len;
    }

    /*
     * @param item RLP encoded bytes
     */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
        uint256 memPtr;
        assembly {
            memPtr := add(item, 0x20)
        }

        return RLPItem(item.length, memPtr);
    }

    /*
     * @dev Create an iterator. Reverts if item is not a list.
     * @param self The RLP item.
     * @return An 'Iterator' over the item.
     */
    function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
        require(isList(self));

        uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
        return Iterator(self, ptr);
    }

    /*
     * @param the RLP item.
     */
    function rlpLen(RLPItem memory item) internal pure returns (uint256) {
        return item.len;
    }

    /*
     * @param the RLP item.
     * @return (memPtr, len) pair: location of the item's payload in memory.
     */
    function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
        uint256 offset = _payloadOffset(item.memPtr);
        uint256 memPtr = item.memPtr + offset;
        uint256 len = item.len - offset; // data length
        return (memPtr, len);
    }

    /*
     * @param the RLP item.
     */
    function payloadLen(RLPItem memory item) internal pure returns (uint256) {
        (, uint256 len) = payloadLocation(item);
        return len;
    }

    /*
     * @param the RLP item containing the encoded list.
     */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
        require(isList(item));

        uint256 items = numItems(item);
        RLPItem[] memory result = new RLPItem[](items);

        uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 dataLen;
        for (uint256 i = 0; i < items; i++) {
            dataLen = _itemLength(memPtr);
            result[i] = RLPItem(dataLen, memPtr);
            memPtr = memPtr + dataLen;
        }

        require(memPtr - item.memPtr == item.len);

        return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
        if (item.len == 0) return false;

        uint8 byte0;
        uint256 memPtr = item.memPtr;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < LIST_SHORT_START) return false;
        return true;
    }

    /*
     * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
     * @return keccak256 hash of RLP encoded bytes.
     */
    function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        uint256 ptr = item.memPtr;
        uint256 len = item.len;
        bytes32 result;
        assembly {
            result := keccak256(ptr, len)
        }
        return result;
    }

    /*
     * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
     * @return keccak256 hash of the item payload.
     */
    function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        (uint256 memPtr, uint256 len) = payloadLocation(item);
        bytes32 result;
        assembly {
            result := keccak256(memPtr, len)
        }
        return result;
    }

    /** RLPItem conversions into data types **/

    // @returns raw rlp encoding in bytes
    function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
        bytes memory result = new bytes(item.len);
        if (result.length == 0) return result;

        uint256 ptr;
        assembly {
            ptr := add(0x20, result)
        }

        copy(item.memPtr, ptr, item.len);
        return result;
    }

    // any non-zero byte except "0x80" is considered true
    function toBoolean(RLPItem memory item) internal pure returns (bool) {
        require(item.len == 1);
        uint256 result;
        uint256 memPtr = item.memPtr;
        assembly {
            result := byte(0, mload(memPtr))
        }

        // SEE Github Issue #5.
        // Summary: Most commonly used RLP libraries (i.e Geth) will encode
        // "0" as "0x80" instead of as "0". We handle this edge case explicitly
        // here.
        if (result == 0 || result == STRING_SHORT_START) {
            return false;
        } else {
            return true;
        }
    }

    function toAddress(RLPItem memory item) internal pure returns (address) {
        // 1 byte for the length prefix
        require(item.len == 21);

        return address(uint160(toUint(item)));
    }

    function toUint(RLPItem memory item) internal pure returns (uint256) {
        require(item.len > 0 && item.len <= 33);

        (uint256 memPtr, uint256 len) = payloadLocation(item);

        uint256 result;
        assembly {
            result := mload(memPtr)

            // shift to the correct location if neccesary
            if lt(len, 32) {
                result := div(result, exp(256, sub(32, len)))
            }
        }

        return result;
    }

    // enforces 32 byte length
    function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
        // one byte prefix
        require(item.len == 33);

        uint256 result;
        uint256 memPtr = item.memPtr + 1;
        assembly {
            result := mload(memPtr)
        }

        return result;
    }

    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
        require(item.len > 0);

        (uint256 memPtr, uint256 len) = payloadLocation(item);
        bytes memory result = new bytes(len);

        uint256 destPtr;
        assembly {
            destPtr := add(0x20, result)
        }

        copy(memPtr, destPtr, len);
        return result;
    }

    /*
     * Private Helpers
     */

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint256) {
        if (item.len == 0) return 0;

        uint256 count = 0;
        uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;
        while (currPtr < endPtr) {
            currPtr = currPtr + _itemLength(currPtr); // skip over an item
            count++;
        }

        return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint256 memPtr) private pure returns (uint256) {
        uint256 itemLen;
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            itemLen = 1;
        } else if (byte0 < STRING_LONG_START) {
            itemLen = byte0 - STRING_SHORT_START + 1;
        } else if (byte0 < LIST_SHORT_START) {
            assembly {
                let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                memPtr := add(memPtr, 1) // skip over the first byte

                /* 32 byte word size */
                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
                itemLen := add(dataLen, add(byteLen, 1))
            }
        } else if (byte0 < LIST_LONG_START) {
            itemLen = byte0 - LIST_SHORT_START + 1;
        } else {
            assembly {
                let byteLen := sub(byte0, 0xf7)
                memPtr := add(memPtr, 1)

                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            return 0;
        } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
            return 1;
        } else if (byte0 < LIST_SHORT_START) {
            // being explicit
            return byte0 - (STRING_LONG_START - 1) + 1;
        } else {
            return byte0 - (LIST_LONG_START - 1) + 1;
        }
    }

    /*
     * @param src Pointer to source
     * @param dest Pointer to destination
     * @param len Amount of memory to copy from the source
     */
    function copy(uint256 src, uint256 dest, uint256 len) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        if (len > 0) {
            // left over bytes. Mask is used to remove unwanted bytes from the word
            uint256 mask = 256**(WORD_SIZE - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask)) // zero out src
                let destpart := and(mload(dest), mask) // retrieve the bytes
                mstore(dest, or(destpart, srcpart))
            }
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.27;

// Had to keep it copypasted as the og lib https://github.com/bakaoh/solidity-rlp-encode has incompatible solc version

import "byteslib/BytesLib.sol";

/**
 * @title RLPEncoder
 * @dev A simple RLP encoding library.
 * @author Bakaoh
 */
library RLPEncoder {
    using BytesLib for bytes;

    /*
     * Internal functions
     */

    /**
     * @dev RLP encodes a byte string.
     * @param self The byte string to encode.
     * @return The RLP encoded string in bytes.
     */
    function encodeBytes(bytes memory self) internal pure returns (bytes memory) {
        bytes memory encoded;
        if (self.length == 1 && uint8(self[0]) < 128) {
            encoded = self;
        } else {
            encoded = encodeLength(self.length, 128).concat(self);
        }
        return encoded;
    }

    /**
     * @dev RLP encodes a uint.
     * @param self The uint to encode.
     * @return The RLP encoded uint in bytes.
     */
    function encodeUint(uint256 self) internal pure returns (bytes memory) {
        return encodeBytes(toBinary(self));
    }

    /**
     * @dev Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
     * @param self The length of the string or the payload.
     * @param offset 128 if item is string, 192 if item is list.
     * @return RLP encoded bytes.
     */
    function encodeLength(uint256 self, uint256 offset) internal pure returns (bytes memory) {
        bytes memory encoded;
        if (self < 56) {
            encoded = new bytes(1);
            encoded[0] = bytes32(self + offset)[31];
        } else {
            uint256 lenLen;
            uint256 i = 1;
            while (self / i != 0) {
                lenLen++;
                i *= 256;
            }

            encoded = new bytes(lenLen + 1);
            encoded[0] = bytes32(lenLen + offset + 55)[31];
            for (i = 1; i <= lenLen; i++) {
                encoded[i] = bytes32((self / (256 ** (lenLen - i))) % 256)[31];
            }
        }
        return encoded;
    }

    /*
     * Private functions
     */

    /**
     * @dev Encode integer in big endian binary form with no leading zeroes.
     * @notice TODO: This should be optimized with assembly to save gas costs.
     * @param _x The integer to encode.
     * @return RLP encoded bytes.
     */
    function toBinary(uint256 _x) private pure returns (bytes memory) {
        bytes memory b = new bytes(32);
        assembly {
            mstore(add(b, 32), _x)
        }
        uint256 i;
        for (i = 0; i < 32; i++) {
            if (b[i] != 0) {
                break;
            }
        }
        bytes memory res = new bytes(32 - i);
        for (uint256 j = 0; j < res.length; j++) {
            res[j] = b[i++];
        }
        return res;
    }
}

// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;


library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
        internal
        pure
        returns (bytes memory)
    {
        // We're using the unchecked block below because otherwise execution ends 
        // with the native overflow error code.
        unchecked {
            require(_length + 31 >= _length, "slice_overflow");
        }
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Settings
{
  "remappings": [
    "openzeppelin/=node_modules/@openzeppelin/contracts/",
    "account-abstraction/=node_modules/account-abstraction/contracts/",
    "erc7739Validator/=node_modules/erc7739-validator-base/src/",
    "solady/=node_modules/solady/src/",
    "forge-std/=lib/forge-std/src/",
    "erc7579/=node_modules/erc7579/src/",
    "EnumerableSet4337/=node_modules/enumerablemap4337/src/",
    "byteslib/=node_modules/solidity-bytes-utils/contracts/",
    "rlp-reader/=node_modules/Solidity-RLP/contracts/",
    "murky-trees/=node_modules/murky/src/",
    "sentinellist/=node_modules/@rhinestone/sentinellist/src/",
    "@ERC4337/=node_modules/@ERC4337/",
    "@erc7579/=node_modules/@erc7579/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@prb/=node_modules/@prb/",
    "@rhinestone/=node_modules/@rhinestone/",
    "@safe-global/=node_modules/@safe-global/",
    "@zerodev/=node_modules/@zerodev/",
    "ExcessivelySafeCall/=node_modules/erc7739-validator-base/node_modules/excessively-safe-call/src/",
    "account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/",
    "ds-test/=node_modules/ds-test/",
    "enumerablemap4337/=node_modules/enumerablemap4337/",
    "enumerableset4337/=node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/",
    "erc4337-validation/=node_modules/erc7739-validator-base/node_modules/@rhinestone/erc4337-validation/src/",
    "erc7739-validator-base/=node_modules/erc7739-validator-base/",
    "excessively-safe-call/=node_modules/excessively-safe-call/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "kernel/=node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/",
    "module-bases/=node_modules/erc7739-validator-base/node_modules/@rhinestone/module-bases/src/",
    "modulekit/=node_modules/erc7739-validator-base/node_modules/@rhinestone/modulekit/src/",
    "murky/=node_modules/murky/",
    "safe7579/=node_modules/erc7739-validator-base/node_modules/@rhinestone/safe7579/src/",
    "solarray/=node_modules/solarray/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "solidity-rlp/=node_modules/solidity-rlp/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"InvalidTargetAddress","type":"error"},{"inputs":[],"name":"ModuleAlreadyInitialized","type":"error"},{"inputs":[],"name":"NewOwnerIsNotEOA","type":"error"},{"inputs":[],"name":"NoOwnerProvided","type":"error"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"OwnerCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"PermitFailed","type":"error"},{"inputs":[],"name":"SafeSendersLengthInvalid","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"addSafeSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"typeId","type":"uint256"}],"name":"isModuleType","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"smartAccount","type":"address"}],"name":"isSafeSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidSignatureWithSender","outputs":[{"internalType":"bytes4","name":"sigValidationResult","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onInstall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"onUninstall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"removeSafeSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"smartAccountOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supportsNestedTypedDataSign","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"validateSignatureWithData","outputs":[{"internalType":"bool","name":"validSig","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

6080806040523460155761384a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806306fdde03146101145780630807dbc11461010f5780632e5b63a61461010a57806354fd4d50146101055780635c81ca68146101005780636d61fe70146100fb5780638a91b0e3146100f6578063940d3840146100f157806397003203146100ec578063d60b347f146100e7578063d620c85a146100e2578063e824b568146100dd578063ecd05961146100d8578063f2fde38b146100d3578063f551e2ee146100ce5763fa544161146100c9575f80fd5b61083c565b6107dc565b610744565b61070c565b6106dd565b6106a3565b610655565b610609565b610558565b6104ae565b610356565b6102c8565b610271565b61022d565b6101ca565b610151565b5f91031261012357565b5f80fd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b34610123575f366003190112610123576101a86040516101726040826108a9565b600e81527f4b314d656556616c696461746f72000000000000000000000000000000000000602082015260405191829182610127565b0390f35b6001600160a01b0381160361012357565b35906101c8826101ac565b565b346101235760403660031901126101235760206102226004356101ec816101ac565b6001600160a01b0360243591610201836101ac565b165f526002835260405f20906001600160a01b03165f5260205260405f2090565b541515604051908152f35b34610123576020366003190112610123576001600160a01b03600435610252816101ac565b165f525f60205260206001600160a01b0360405f205416604051908152f35b34610123575f366003190112610123576101a86040516102926040826108a9565b600581527f312e302e33000000000000000000000000000000000000000000000000000000602082015260405191829182610127565b34610123576020366003190112610123576102f76001600160a01b036004356102f0816101ac565b16336117ba565b005b9181601f840112156101235782359167ffffffffffffffff8311610123576020838186019501011161012357565b6020600319820112610123576004359067ffffffffffffffff821161012357610352916004016102f9565b9091565b346101235761036436610327565b90811561048657610391336001600160a01b03165f525f6020526001600160a01b0360405f205416151590565b61045e576103b16103ab6103a58484610948565b906109d2565b60601c90565b6103c56001600160a01b0382161515610a12565b6103ce81610d8c565b61043657610418906103f0336001600160a01b03165f525f60205260405f2090565b906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b6014821161042257005b816102f79261043092610956565b90610e39565b7fffddfca0000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe72ce85e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1f2a381c000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610123576104bc36610327565b5050335f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff198154169055335f52600160205260405f20546001905b808211156104ff57005b8181039181831161055357335f52600160205260405f2080548410156105425761053690600161053c94950160051b01543361208a565b506118a1565b906104f5565b83638277484f5f526020526024601cfd5b610da3565b346101235760603660031901126101235760043560243567ffffffffffffffff81116101235761058c9036906004016102f9565b60443567ffffffffffffffff8111610123576105ac9036906004016102f9565b601481949294106105e157601411610123576101a8936105cf933560601c610ec5565b60405190151581529081906020820190565b7fdfe93090000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101235760403660031901126101235760043567ffffffffffffffff81116101235761012060031982360301126101235761064d60209160243590600401610aed565b604051908152f35b34610123576020366003190112610123576020610699600435610677816101ac565b6001600160a01b03165f525f6020526001600160a01b0360405f205416151590565b6040519015158152f35b34610123575f3660031901126101235760206040517fd620c85a000000000000000000000000000000000000000000000000000000008152f35b34610123576020366003190112610123576102f76001600160a01b03600435610705816101ac565b163361208a565b3461012357602036600319011261012357602060043560018114908115610739575b506040519015158152f35b60079150145f61072e565b3461012357602036600319011261012357600435610761816101ac565b6001600160a01b038116156107b45761077981610d8c565b610436576102f790335f525f60205260405f20906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b7f8579befe000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610123576060366003190112610123576004356107f9816101ac565b60443560243567ffffffffffffffff82116101235760209261082261082a9336906004016102f9565b929091610c58565b6001600160e01b031960405191168152f35b3461012357602036600319011261012357602061086360043561085e816101ac565b610d48565b6001600160a01b0360405191168152f35b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176108a457604052565b610874565b90601f8019910116810190811067ffffffffffffffff8211176108a457604052565b604051906101c86101a0836108a9565b604051906101c8610120836108a9565b604051906101c860e0836108a9565b604051906101c86040836108a9565b604051906101c86080836108a9565b67ffffffffffffffff81116108a457601f01601f191660200190565b604051906109436020836108a9565b5f8252565b906014116101235790601490565b909291928360141161012357831161012357601401916013190190565b906004116101235790600490565b909291928360041161012357831161012357600401916003190190565b909291928360011161012357831161012357600101915f190190565b90939293848311610123578411610123578101920390565b356bffffffffffffffffffffffff198116929190601482106109f2575050565b6bffffffffffffffffffffffff1960149290920360031b82901b16169150565b15610a1957565b7fc81abf60000000000000000000000000000000000000000000000000000000005f5260045ffd5b35610a4b816101ac565b90565b903590601e1981360301821215610123570180359067ffffffffffffffff82116101235760200191813603831361012357565b919091356001600160e01b031981169260048110610a9d575050565b6001600160e01b0319929350829060040360031b1b161690565b929192610ac382610918565b91610ad160405193846108a9565b829481845281830111610123578281602093845f960137010152565b90610afa61085e83610a41565b906101008301926004610b0d8583610a4e565b9050105f14610b3357610b26610a4b94610b2d92610a4e565b3691610ab7565b90610f66565b6001600160e01b0319610b58610b52610b4c8785610a4e565b90610973565b90610a81565b16620bbf7760e91b8103610b855750610b77610a4b94610b7e92610a4e565b8091610981565b509061154e565b63177eee0160e01b8103610bbf57508084610bb1610ba9610a4b97610bb995610a4e565b929093610a4e565b929050610981565b91611494565b630bbf770160e11b03610be257610b77610a4b94610bdc92610a4e565b9161112f565b610b26610a4b94610b2d92610a4e565b919091357fffffff000000000000000000000000000000000000000000000000000000000081169260038110610c26575050565b7fffffff0000000000000000000000000000000000000000000000000000000000929350829060030360031b1b161690565b90918360031161012357620bbf7760e91b7fffffff0000000000000000000000000000000000000000000000000000000000610c95600384610bf2565b1614610cb057610a4b93610ca8916115f6565b929091611628565b919050610d0b610d1393610cc333610d48565b60408051602081019586523360601b6bffffffffffffffffffffffff191691810191909152909390610d0281605481015b03601f1981018352826108a9565b519020936115f6565b929091610ec5565b15610d3c577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b6001600160e01b031990565b6001600160a01b0381165f525f6020526001600160a01b0360405f20541680155f14610d72575090565b905090565b6001600160a01b03610a4b9216906001611841565b3b8015159081610d9a575090565b60179150141590565b634e487b7160e01b5f52601160045260245ffd5b8115610dc1570490565b634e487b7160e01b5f52601260045260245ffd5b908160051b918083046020149015171561055357565b908160081b91808304610100149015171561055357565b906001820180921161055357565b90601b820180921161055357565b906037820180921161055357565b9190820180921161055357565b9060148106610e9d575f5b601482048110610e5357505050565b806014029060148204810361055357610e6b81610e02565b8060140290601482040361055357610e906103ab6103a5610e9693600196888a6109ba565b33610d77565b5001610e44565b7f1c6b73d6000000000000000000000000000000000000000000000000000000005f5260045ffd5b919290926001600160e01b0319610edf610b528484610973565b16620bbf7760e91b8103610f04575081610a4b9492610efd92610981565b5091611c20565b63177eee0160e01b8103610f2b575081610a4b949392610f2392610981565b929091611ab1565b630bbf770160e11b03610f505781610a4b949392610f4892610981565b9290916119f9565b610f6090610a4b94923691610ab7565b91611c74565b610f6f92611c74565b15610f78575f90565b600190565b3590811515820361012357565b359065ffffffffffff8216820361012357565b60ff81160361012357565b35906101c882610f9d565b67ffffffffffffffff81116108a45760051b60200190565b929190610fd781610fb3565b93610fe560405195866108a9565b602085838152019160051b810192831161012357905b82821061100757505050565b8135815260209182019101610ffb565b9080601f8301121561012357816020610a4b93359101610fcb565b6101a081360312610123576110456108cb565b9061104f816101bd565b825261105d602082016101bd565b602083015260408101356040830152606081013560608301526080810135608083015261108c60a08201610f7d565b60a083015260c081013560c08301526110a760e08201610f8a565b60e08301526110b96101008201610f8a565b6101008301526110cc6101208201610fa8565b6101208301526101408101356101408301526101608101356101608301526101808101359067ffffffffffffffff82116101235761110c91369101611017565b61018082015290565b6040513d5f823e3d90fd5b90816020910312610123575190565b92915061113e90602001611032565b60e081019161117d611156845165ffffffffffff1690565b61010084019565ffffffffffff80611174895165ffffffffffff1690565b16921690611cdf565b6111878383611d26565b9261014081018051906111fb6111f76101608501978851906111f16101208801966111e36111b6895160ff1690565b6040519586936020850191926041936001600160f81b0319928452602084015260f81b1660408201520190565b03601f1981018452836108a9565b88611c74565b1590565b611487576112196111f76101808501519560c0860196875190611dec565b6114875760a0830151611271575b505050505050611250611243610a4b935165ffffffffffff1690565b915165ffffffffffff1690565b6001600160d01b031965ffffffffffff60a01b9160d01b169160a01b161790565b61129161128584516001600160a01b031690565b6001600160a01b031690565b9360208401946112a886516001600160a01b031690565b60608601986112bc8a519451965160ff1690565b9451905190833b156101235761133f5f96928b9288946040519a8b998a9889977fd505accf000000000000000000000000000000000000000000000000000000008952600489019360c09591989796936001600160a01b0360ff948160e089019c1688521660208701526040860152606085015216608083015260a08201520152565b03925af1908161146d575b5061145a57916020916113826113746112856112856112856113cf9998516001600160a01b031690565b91516001600160a01b031690565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b039384166004820152921660248301529093849190829081906044820190565b03915afa918215611455575f92611424575b5051116113fc57611250611243610a4b935b935f8080611227565b7fb78cb0dd000000000000000000000000000000000000000000000000000000005f5260045ffd5b61144791925060203d60201161144e575b61143f81836108a9565b810190611120565b905f6113e1565b503d611435565b611115565b50505050611250611243610a4b936113f3565b8061147b5f611481936108a9565b80610119565b5f61134a565b5050505050505050600190565b929161149f91611ef7565b9060e08201916115086111f76114dc6114be865165ffffffffffff1690565b61010085019765ffffffffffff806111748b5165ffffffffffff1690565b936040840151906114fd6060860151926111e36111b6602089015160ff1690565b608085015190611c74565b61154557611524918160a060c06111f794015191015190611dec565b61153e57611250611243610a4b935165ffffffffffff1690565b5050600190565b50505050600190565b9091823591602084013592604085013594606081013501926115a484359183610f606115938560051b89019765ffffffffffff8c169065ffffffffffff8c1690611cdf565b963690604060208201359101610ab7565b156115eb576115c0936115bb916020369201610fcb565b611dec565b1561153e57610a4b91906001600160d01b031965ffffffffffff60a01b9160d01b169160a01b161790565b505050505050600190565b9182828101601f19013561649261ffff30801c190402146116145750565b604091935080925001350160208135910191565b9291908215611755575b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060208301351161172d576001600160a01b035f94166dd9ecebf3c23529de49815dac1c4c8114908115611723575b81156116f3575b506116d3575b83156116c0575b83156116ae575b505050155f03631626ba7e1760e01b90565b6116b89350612567565b5f808061169c565b92506116cd828285612296565b92611695565b92506116ed6116e133610d48565b84610f60368686610ab7565b9261168e565b90505f52600260205261171a3360405f20906001600160a01b03165f5260205260405f2090565b5415155f611688565b3381149150611681565b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b61773961ffff84190402810361163257505050507f773900010000000000000000000000000000000000000000000000000000000090565b6001906117b4935f520160205260405f20906001600160a01b03165f5260205260405f2090565b54151590565b815f52600180016020526117e28160405f20906001600160a01b03165f5260205260405f2090565b5461183b5780611835915f52600160205260405f20600181540190848260051b82015555805f52600160205260405f2054925f52600260205260405f20906001600160a01b03165f5260205260405f2090565b55600190565b50505f90565b9061184d83828461178d565b61189a575f81815260208390526040902080546001908101600581901b830186905591829055611835939091945f520160205260405f20906001600160a01b03165f5260205260405f2090565b5050505f90565b5f1981146105535760010190565b5f1981019190821161055357565b60051981019190821161055357565b60221981019190821161055357565b601f1981019190821161055357565b60bf1981019190821161055357565b607f1981019190821161055357565b602003906020821161055357565b9190820391821161055357565b91909161012081840312610123576119396108db565b92611943826101bd565b84526020820135602085015260408201356040850152606082013560608501526080820135608085015261197960a08301610fa8565b60a085015260c082013560c085015260e082013560e085015261010082013567ffffffffffffffff8111610123576119b19201611017565b610100830152565b35610a4b81610f9d565b903590601e1981360301821215610123570180359067ffffffffffffffff821161012357602001918160051b3603831361012357565b919250611a786111f76020850193611a1a611a143687611923565b8261261a565b61010087013591611a7360e0890135611a65611a3860c08c016119b9565b6040519687936020850191926041936001600160f81b0319928452602084015260f81b1660408201520190565b03601f1981018552846108a9565b611c74565b61189a5760a06115bb84611a976111f795610120611aa49801906119c3565b9390910135923691610fcb565b611aad57600190565b5f90565b611ab96126a1565b50611ac48484611ea7565b3560f81c92611ad2856118af565b611add908683611eb5565b3560f81c611aea81610dd5565b611af390610e02565b611afd9087611916565b611b0890878461099e565b909290611b16368286610ab7565b611b1f906127aa565b91611b29836127d7565b611b3390896128f2565b93888551611b4090612a16565b9360208701978851986040890191825198611b5a9061315f565b9190508a5192519351943690611b6f92610ab7565b611b7895612ac0565b9460600151611b8690612c41565b99611b9092612e9f565b96611b996108eb565b60ff918216815291166020820181905260408201859052606082018390526080820193845260a0820198895260c090910196875260408051602081019590955284019190915260f81b6001600160f81b031916606083015260418252611c006061836108a9565b51611c0a92611c74565b1561189a57611aa4926111f79251905190611dec565b9180359060208101350192611c4b84359183610f608460051b88013690604060208201359101610ab7565b15611c6c57611c62936115bb916020369201610fcb565b15611aad57600190565b505050505f90565b906001600160a01b03929183611c8a84846126e8565b911693168314611cd7576001600160a01b0391611ccd916020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004206126e8565b1614610f78575f90565b505050600190565b9160405191602083019384526040830152606082015260608152611d046080826108a9565b5190206040516020810191825260208152611d206040826108a9565b51902090565b90604060429260c0830151611db06001600160a01b03602086015116610cf46060870151936080880151875195869460208601988991926001600160a01b0360a09497969592978160c08601997f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98752166020860152166040840152606083015260808201520152565b51902091015190604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b929091905f915b8451831015611e3557611e06838661277e565b519081811015611e24575f52602052600160405f205b920191611df3565b905f52602052600160405f20611e1c565b915092501490565b60405190610120820182811067ffffffffffffffff8211176108a4576040525f610100838281528260208201528260408201528260608201528260808201528260a0820152606060c08201528260e08201520152565b634e487b7160e01b5f52603260045260245ffd5b9015611eb05790565b611e93565b90821015611eb0570190565b919091356001600160d01b031981169260068110611edd575050565b6001600160d01b0319929350829060060360031b1b161690565b611eff611e3d565b50611f0a8282611ea7565b3560f81c91600c91611f1c8383611916565b611f25836118bd565b611f309184846109ba565b611f3991611ec1565b60d01c9180611f47816118bd565b90611f539181856109ba565b611f5c91611ec1565b60d01c93611f6a8183611916565b611f73906118af565b611f7e908385611eb5565b3560f81c90611f8c82610dd5565b611f9590610e02565b90611f9f91610e2c565b611fa99083611916565b611fb490838561099e565b9390611fc1368683610ab7565b611fca906127aa565b91611fd4836127d7565b611fde908a6128f2565b93898551611feb90612a16565b97602087019485519560408901918251986120059061315f565b9190508a519251935194369061201a92610ab7565b61202395612ac0565b946060015161203190612c41565b9561203b92612d4e565b946120446108db565b60ff909916895260ff16602089015260408801526060870152608086015260a085015260c084015265ffffffffffff1660e083015265ffffffffffff1661010082015290565b90805f5260026020526120b18260405f20906001600160a01b03165f5260205260405f2090565b5491821561189a575f19830191838311610553575f828152600160205260409020545f19810191908211610553575f94848484612110956118359803612126575b509050612101915060016134a7565b6002905f5260205260405f2090565b906001600160a01b03165f5260205260405f2090565b6121469261210161213c6121109385600161345a565b8092856001613489565b555f8084816120f2565b81601f820112156101235780519061216782610918565b9261217560405194856108a9565b8284526020838301011161012357815f9260208093018386015e8301015290565b51906101c8826101ac565b9080601f830112156101235781516121b881610fb3565b926121c660405194856108a9565b81845260208085019260051b82010192831161012357602001905b8282106121ee5750505090565b81518152602091820191016121e1565b9060e0828203126101235781516001600160f81b0319811681036101235792602083015167ffffffffffffffff8111610123578261223d918501612150565b92604081015167ffffffffffffffff8111610123578361225e918301612150565b9260608201519261227160808401612196565b9260a08101519260c082015167ffffffffffffffff811161012357610a4b92016121a1565b90923093306124bf575b60405190600119858201013560f01c94600e830196869187810384016041198101976119015f5260408960203789158a604201841017816042601e20181761247f57507f5479706564446174615369676e2800000000000000000000000000000000000086526001198101999889818c82378188016028600e8201526029600d8201515f1a03612429575b506f07fffffe000000000000010000000000919250999899515f1a1c5b88515f1a602881146123695790651201000000016001921c17980197612348565b50929496999086986040610a4b9b83605c96989a957f20636f6e74656e74732c737472696e67206e616d652c737472696e670000000085527f2076657273696f6e2c75696e7432353620636861696e49642c61646472657373601c8601527f20766572696679696e67436f6e74726163742c627974657333322073616c7429603c8601528785013788370103018620835260e08320604052600116604201601e2092604119910301935b604052612dcb576124249033612ddc565b612dcb565b60015f5b016029600d82840301515f1a14848210111561244b5760019061242d565b6028915080806040600e936f07fffffe000000000000010000000000970397886041199101010185378a010153829161232b565b949699505095505050610a4b94505f907f983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de5f5260205260405f2091612413565b6040516342580cb760e11b815294505f85600481335afa8015611455575f955f5f905f925f9461252e575b50906001600160a01b039291604051996020815191012060408b01526020815191012060608a015260808901521660a087015260c086015260e085016040526122a0565b925050506001600160a01b03965061255891503d805f833e61255081836108a9565b8101906121fe565b509399939450929091906124ea565b92915f933a1561257657505050565b90919293503a3a5260203a3a386d378edcd5b5b0a24f5342d8c1048561fffffa503a51156125b7575b610f60610a4b936125af33610d48565b933691610ab7565b60405192631626ba7e3a526d378edcd5b5b0a24f5342d8c1048560205260408052454561ffff011790815a106d378edcd5b5b0a24f5342d8c1048584141761261857610a4b94610f60923a906064601c3a923090fa5060405293505061259f565bfe5b9060206042926080830151611db06001600160a01b03855116610cf46040870151936060880151604051958694898601988991926001600160a01b0360a09497969592978160c08601997f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98752166020860152166040840152606083015260808201520152565b6040519060e0820182811067ffffffffffffffff8211176108a457604052606060c0835f81525f60208201525f60408201525f838201525f60808201525f60a08201520152565b9190915f92604051918151806040146127405760411461270757505050565b602092945060608201515f1a835260408201516060525b5f5201516040526020604060805f60015afa505f6060523d6060185191604052565b5060209294507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040830151601b8160ff1c0185521660605261271e565b8051821015611eb05760209160051b010190565b6040519061279f82610888565b5f6020838281520152565b6127b2612792565b506020815191604051926127c584610888565b835201602082015290565b1561012357565b906127e182612f08565b15610123576127ef82612f28565b916127f983610fb3565b9061280760405192836108a9565b838252601f1961281685610fb3565b015f5b8181106128a65750506020810161283a815161283481612f89565b90610e2c565b945f905b808210612860575050610a4b929394612858915190611916565b9051146127d0565b909561289e81612871600193612ff4565b9061287a6108fa565b82815281602082015261288d8b8a61277e565b526128988a8961277e565b50610e2c565b96019061283e565b6020906128b1612792565b82828701015201612819565b604051906080820182811067ffffffffffffffff8211176108a457604052606080835f81525f60208201525f60408201520152565b60ff906128fd6128bd565b5016806129775750600560069061295961295360079460ff61294b612935826129436129358261293b6129358260089e5b168a61277e565b51613072565b9c168761277e565b98168461277e565b94169061277e565b51613123565b91612962610909565b93845260208401526040830152606082015290565b6002036129ab576007600990612959612953600a9460ff61294b612935826129436129358261293b61293582600b9e61292e565b60405162461bcd60e51b815260206004820152602860248201527f547856616c696461746f724c69623a3a20756e737570706f727465642065766d60448201527f20747820747970650000000000000000000000000000000000000000000000006064820152608490fd5b60258110612a7757612a278161314d565b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116810361055357612a6c612a67610a4b93612a719360011b90611916565b6118cc565b610e10565b60ff1690565b60018111612a7157601b81018091116105535760ff1690565b805191908290602001825e015f815290565b6001906001600160f81b0319610a4b949360f81b1681520190612a90565b94612b1a9192612b10612b08612afc612b1f94612af5612ae9612aee612ae9612b259c9d613634565b6136b0565b5192613634565b5190610e2c565b612af5612ae98a613634565b918551611916565b9283918551611916565b611916565b91613290565b9060ff831660028103612b5d575050611d20612b4c610cf492612b46610934565b90613316565b604051928391602083019586612aa2565b91925090612bd75760258110612bca57612bc091612bbb612b88612b83612bb59461314d565b61318b565b6111e3612b96612ae961358f565b612bb5612ba4612ae961358f565b916040519788956020870190612a90565b90612a90565b613316565b6020815191012090565b50612bc090612b46610934565b60405162461bcd60e51b8152602060048201526024808201527f547856616c696461746f724c69623a3a20756e737570706f727465642074782060448201527f74797065000000000000000000000000000000000000000000000000000000006064820152608490fd5b6020815110612c83578051601f19810190811161055357612c619161322d565b602081519101519060208110612c75575090565b5f199060200360031b1b1690565b608460405162461bcd60e51b815260206004820152602560248201527f54784465636f6465723a3a2063616c6c44617461206c656e67746820746f6f2060448201527f73686f72740000000000000000000000000000000000000000000000000000006064820152fd5b90612cf782610fb3565b612d0460405191826108a9565b8281528092612d15601f1991610fb3565b0190602036910137565b60ff168015610553575f190190565b359060208110612c75575090565b60ff5f199116019060ff821161055357565b929190612d5d60ff8316612ced565b93600b198201828111610553575f198101908111610553579291925b60ff8316612d875750505050565b612dbf81612dab612da582612d9e612dc5966118db565b89886109ba565b90612d2e565b612db960ff61292e88612d3c565b526118db565b92612d1f565b91612d79565b610f60610a4b93926125af33610d48565b5f6001600160a01b03916004604051809481936342580cb760e11b8352165afa9081156114555760a0915f915f5f915f93612e7a575b50604051937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f855260208151910120602085015260208151910120604084015260608301526080820152206719010000000000005f52601a52603a526042601820905f603a52565b92505050612e9291503d805f833e61255081836108a9565b509394509250905f612e12565b9291612ead60ff8216612ced565b935f198301838111610553575b60ff8316612ec85750505050565b601f19810181811161055357612ee6612da5612f02938388876109ba565b612efb60ff612ef487612d3c565b168961277e565b5292612d1f565b91612eba565b805115612f2357602060c0910151515f1a10611aad57600190565b505f90565b805115612f23575f9060208101908151612f4181612f89565b8101809111610553579151905181018091116105535791905b828110612f675750905090565b612f7081612ff4565b810180911161055357612f8390916118a1565b90612f5a565b515f1a6080811015612f9a57505f90565b60b881108015612fde575b15612fb05750600190565b60c0811015612fcf57610a4b90612fca9060b75b90611916565b610e02565b610a4b90612fca9060f7612fc4565b5060c08110158015612fa5575060f88110612fa5565b80515f1a906080821015613009575050600190565b60b882101561301f5750612fca610a4b916118f9565b60c08210156130425760010151602082900360b7016101000a90040160b5190190565b60f88210156130585750612fca610a4b916118ea565b60010151602082900360f7016101000a90040160f5190190565b805180151590816130a8575b50156101235761308d9061315f565b9051906020811061309c575090565b6020036101000a900490565b6021915011155f61307e565b604080519091906130c583826108a9565b60208152918290601f190190369060200137565b604080519091906130ea83826108a9565b6001815291601f1901366020840137565b9061310582610918565b61311260405191826108a9565b8281528092612d15601f1991610918565b80511561012357613136610a4b9161315f565b613142819392936130fb565b9283602001906134fe565b60221981019081116105535760011c90565b90602082019161316f8351612f89565b9251908382018092116105535751928303928311610553579190565b612ae9610a4b91613634565b1561319e57565b606460405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152fd5b156131e957565b606460405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152fd5b906132386001613197565b815160208201808311610553576132509110156131e2565b6040519160208084019260408501920101905b80831061327d57505060208252601f01601f191660405290565b9091602080918451815201920190613263565b916132a081601f81011015613197565b6132b683516132af8385610e2c565b11156131e2565b806132ce575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b8084106133035750508252601f01601f191660405290565b90926020809185518152019301906132eb565b61333190610cf4612bb5936040519485936020850190612a90565b805190603882101561338557612bb591610cf4610a4b926001600160f81b031961336460c061335e6130d9565b95610e2c565b60f81b165f1a61337384613571565b535b6040519485936020850190612a90565b916001915f5b6133958483610db7565b156133b2576133a66133ac916118a1565b93610deb565b9261338b565b9092509290926133c96133c482610e02565b6130fb565b926001600160f81b03196133e66133e160c085610e2c565b610e1e565b60f81b165f1a6133f585613571565b5360015b8281111561341457505050612bb591610cf4610a4b92613375565b806001600160f81b031961343f612a716134396134346134559689611916565b6134ef565b86610db7565b60f81b165f1a61344f828861357e565b536118a1565b6133f9565b905f5260205260405f209081548110156134795760010160051b015490565b638277484f5f526020526024601cfd5b905f5260205260405f209081548110156134795760010160051b0155565b905f5260205260405f2080549081156134eb575f198201918083116105535781548310156134da575f9060051b82015555565b82638277484f5f526020526024601cfd5b5050565b601f8111610553576101000a90565b9091801561356c575b602081101561353c578061351a57505050565b61352961343461352e92611908565b6118af565b905182518216911916179052565b919080518252602081018091116105535790602081018091116105535791601f1981019081111561350757610da3565b505050565b805115611eb05760200190565b908151811015611eb0570160200190565b6135976130b4565b905f60208301525f915b60208310613603575b6135b66133c484611908565b905f5b82518110156135fc576001906135e96135db6135d4886118a1565b978561357e565b516001600160f81b03191690565b5f1a6135f5828661357e565b53016135b9565b5090925050565b916136216136146135db838661357e565b6001600160f81b03191690565b61362e57600101916135a1565b916135aa565b9061363d6130b4565b9160208301525f915b6020831061368c575b61365b6133c484611908565b905f5b82518110156135fc576001906136796135db6135d4886118a1565b5f1a613685828661357e565b530161365e565b9161369d6136146135db838661357e565b6136aa5760010191613646565b9161364f565b805160018114908161374a575b50156136c65790565b6136d08151613762565b6040519181518084526020840190840191602083019160208501905b83811061373a5750508051809286518201875293019260208085019201905b82811061372a5750509251603f91011590910101601f19166040525090565b815181526020918201910161370b565b81518152602091820191016136ec565b905015611eb0576080602082015160f81c105f6136bd565b603881101561379a576001600160f81b031961378760806137816130d9565b93610e2c565b60f81b165f1a61379682613571565b5390565b6001915f5b6137a98484610db7565b156137c0576133a66137ba916118a1565b9261379f565b9092506137cf6133c482610e02565b916001600160f81b03196137e76133e1608085610e2c565b60f81b165f1a6137f684613571565b5360015b828111156138085750505090565b806001600160f81b0319613828612a716134396134346138389689611916565b60f81b165f1a61344f828761357e565b6137fa56fea164736f6c634300081b000a

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c806306fdde03146101145780630807dbc11461010f5780632e5b63a61461010a57806354fd4d50146101055780635c81ca68146101005780636d61fe70146100fb5780638a91b0e3146100f6578063940d3840146100f157806397003203146100ec578063d60b347f146100e7578063d620c85a146100e2578063e824b568146100dd578063ecd05961146100d8578063f2fde38b146100d3578063f551e2ee146100ce5763fa544161146100c9575f80fd5b61083c565b6107dc565b610744565b61070c565b6106dd565b6106a3565b610655565b610609565b610558565b6104ae565b610356565b6102c8565b610271565b61022d565b6101ca565b610151565b5f91031261012357565b5f80fd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b34610123575f366003190112610123576101a86040516101726040826108a9565b600e81527f4b314d656556616c696461746f72000000000000000000000000000000000000602082015260405191829182610127565b0390f35b6001600160a01b0381160361012357565b35906101c8826101ac565b565b346101235760403660031901126101235760206102226004356101ec816101ac565b6001600160a01b0360243591610201836101ac565b165f526002835260405f20906001600160a01b03165f5260205260405f2090565b541515604051908152f35b34610123576020366003190112610123576001600160a01b03600435610252816101ac565b165f525f60205260206001600160a01b0360405f205416604051908152f35b34610123575f366003190112610123576101a86040516102926040826108a9565b600581527f312e302e33000000000000000000000000000000000000000000000000000000602082015260405191829182610127565b34610123576020366003190112610123576102f76001600160a01b036004356102f0816101ac565b16336117ba565b005b9181601f840112156101235782359167ffffffffffffffff8311610123576020838186019501011161012357565b6020600319820112610123576004359067ffffffffffffffff821161012357610352916004016102f9565b9091565b346101235761036436610327565b90811561048657610391336001600160a01b03165f525f6020526001600160a01b0360405f205416151590565b61045e576103b16103ab6103a58484610948565b906109d2565b60601c90565b6103c56001600160a01b0382161515610a12565b6103ce81610d8c565b61043657610418906103f0336001600160a01b03165f525f60205260405f2090565b906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b6014821161042257005b816102f79261043092610956565b90610e39565b7fffddfca0000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe72ce85e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1f2a381c000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610123576104bc36610327565b5050335f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff198154169055335f52600160205260405f20546001905b808211156104ff57005b8181039181831161055357335f52600160205260405f2080548410156105425761053690600161053c94950160051b01543361208a565b506118a1565b906104f5565b83638277484f5f526020526024601cfd5b610da3565b346101235760603660031901126101235760043560243567ffffffffffffffff81116101235761058c9036906004016102f9565b60443567ffffffffffffffff8111610123576105ac9036906004016102f9565b601481949294106105e157601411610123576101a8936105cf933560601c610ec5565b60405190151581529081906020820190565b7fdfe93090000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101235760403660031901126101235760043567ffffffffffffffff81116101235761012060031982360301126101235761064d60209160243590600401610aed565b604051908152f35b34610123576020366003190112610123576020610699600435610677816101ac565b6001600160a01b03165f525f6020526001600160a01b0360405f205416151590565b6040519015158152f35b34610123575f3660031901126101235760206040517fd620c85a000000000000000000000000000000000000000000000000000000008152f35b34610123576020366003190112610123576102f76001600160a01b03600435610705816101ac565b163361208a565b3461012357602036600319011261012357602060043560018114908115610739575b506040519015158152f35b60079150145f61072e565b3461012357602036600319011261012357600435610761816101ac565b6001600160a01b038116156107b45761077981610d8c565b610436576102f790335f525f60205260405f20906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b7f8579befe000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610123576060366003190112610123576004356107f9816101ac565b60443560243567ffffffffffffffff82116101235760209261082261082a9336906004016102f9565b929091610c58565b6001600160e01b031960405191168152f35b3461012357602036600319011261012357602061086360043561085e816101ac565b610d48565b6001600160a01b0360405191168152f35b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176108a457604052565b610874565b90601f8019910116810190811067ffffffffffffffff8211176108a457604052565b604051906101c86101a0836108a9565b604051906101c8610120836108a9565b604051906101c860e0836108a9565b604051906101c86040836108a9565b604051906101c86080836108a9565b67ffffffffffffffff81116108a457601f01601f191660200190565b604051906109436020836108a9565b5f8252565b906014116101235790601490565b909291928360141161012357831161012357601401916013190190565b906004116101235790600490565b909291928360041161012357831161012357600401916003190190565b909291928360011161012357831161012357600101915f190190565b90939293848311610123578411610123578101920390565b356bffffffffffffffffffffffff198116929190601482106109f2575050565b6bffffffffffffffffffffffff1960149290920360031b82901b16169150565b15610a1957565b7fc81abf60000000000000000000000000000000000000000000000000000000005f5260045ffd5b35610a4b816101ac565b90565b903590601e1981360301821215610123570180359067ffffffffffffffff82116101235760200191813603831361012357565b919091356001600160e01b031981169260048110610a9d575050565b6001600160e01b0319929350829060040360031b1b161690565b929192610ac382610918565b91610ad160405193846108a9565b829481845281830111610123578281602093845f960137010152565b90610afa61085e83610a41565b906101008301926004610b0d8583610a4e565b9050105f14610b3357610b26610a4b94610b2d92610a4e565b3691610ab7565b90610f66565b6001600160e01b0319610b58610b52610b4c8785610a4e565b90610973565b90610a81565b16620bbf7760e91b8103610b855750610b77610a4b94610b7e92610a4e565b8091610981565b509061154e565b63177eee0160e01b8103610bbf57508084610bb1610ba9610a4b97610bb995610a4e565b929093610a4e565b929050610981565b91611494565b630bbf770160e11b03610be257610b77610a4b94610bdc92610a4e565b9161112f565b610b26610a4b94610b2d92610a4e565b919091357fffffff000000000000000000000000000000000000000000000000000000000081169260038110610c26575050565b7fffffff0000000000000000000000000000000000000000000000000000000000929350829060030360031b1b161690565b90918360031161012357620bbf7760e91b7fffffff0000000000000000000000000000000000000000000000000000000000610c95600384610bf2565b1614610cb057610a4b93610ca8916115f6565b929091611628565b919050610d0b610d1393610cc333610d48565b60408051602081019586523360601b6bffffffffffffffffffffffff191691810191909152909390610d0281605481015b03601f1981018352826108a9565b519020936115f6565b929091610ec5565b15610d3c577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b6001600160e01b031990565b6001600160a01b0381165f525f6020526001600160a01b0360405f20541680155f14610d72575090565b905090565b6001600160a01b03610a4b9216906001611841565b3b8015159081610d9a575090565b60179150141590565b634e487b7160e01b5f52601160045260245ffd5b8115610dc1570490565b634e487b7160e01b5f52601260045260245ffd5b908160051b918083046020149015171561055357565b908160081b91808304610100149015171561055357565b906001820180921161055357565b90601b820180921161055357565b906037820180921161055357565b9190820180921161055357565b9060148106610e9d575f5b601482048110610e5357505050565b806014029060148204810361055357610e6b81610e02565b8060140290601482040361055357610e906103ab6103a5610e9693600196888a6109ba565b33610d77565b5001610e44565b7f1c6b73d6000000000000000000000000000000000000000000000000000000005f5260045ffd5b919290926001600160e01b0319610edf610b528484610973565b16620bbf7760e91b8103610f04575081610a4b9492610efd92610981565b5091611c20565b63177eee0160e01b8103610f2b575081610a4b949392610f2392610981565b929091611ab1565b630bbf770160e11b03610f505781610a4b949392610f4892610981565b9290916119f9565b610f6090610a4b94923691610ab7565b91611c74565b610f6f92611c74565b15610f78575f90565b600190565b3590811515820361012357565b359065ffffffffffff8216820361012357565b60ff81160361012357565b35906101c882610f9d565b67ffffffffffffffff81116108a45760051b60200190565b929190610fd781610fb3565b93610fe560405195866108a9565b602085838152019160051b810192831161012357905b82821061100757505050565b8135815260209182019101610ffb565b9080601f8301121561012357816020610a4b93359101610fcb565b6101a081360312610123576110456108cb565b9061104f816101bd565b825261105d602082016101bd565b602083015260408101356040830152606081013560608301526080810135608083015261108c60a08201610f7d565b60a083015260c081013560c08301526110a760e08201610f8a565b60e08301526110b96101008201610f8a565b6101008301526110cc6101208201610fa8565b6101208301526101408101356101408301526101608101356101608301526101808101359067ffffffffffffffff82116101235761110c91369101611017565b61018082015290565b6040513d5f823e3d90fd5b90816020910312610123575190565b92915061113e90602001611032565b60e081019161117d611156845165ffffffffffff1690565b61010084019565ffffffffffff80611174895165ffffffffffff1690565b16921690611cdf565b6111878383611d26565b9261014081018051906111fb6111f76101608501978851906111f16101208801966111e36111b6895160ff1690565b6040519586936020850191926041936001600160f81b0319928452602084015260f81b1660408201520190565b03601f1981018452836108a9565b88611c74565b1590565b611487576112196111f76101808501519560c0860196875190611dec565b6114875760a0830151611271575b505050505050611250611243610a4b935165ffffffffffff1690565b915165ffffffffffff1690565b6001600160d01b031965ffffffffffff60a01b9160d01b169160a01b161790565b61129161128584516001600160a01b031690565b6001600160a01b031690565b9360208401946112a886516001600160a01b031690565b60608601986112bc8a519451965160ff1690565b9451905190833b156101235761133f5f96928b9288946040519a8b998a9889977fd505accf000000000000000000000000000000000000000000000000000000008952600489019360c09591989796936001600160a01b0360ff948160e089019c1688521660208701526040860152606085015216608083015260a08201520152565b03925af1908161146d575b5061145a57916020916113826113746112856112856112856113cf9998516001600160a01b031690565b91516001600160a01b031690565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b039384166004820152921660248301529093849190829081906044820190565b03915afa918215611455575f92611424575b5051116113fc57611250611243610a4b935b935f8080611227565b7fb78cb0dd000000000000000000000000000000000000000000000000000000005f5260045ffd5b61144791925060203d60201161144e575b61143f81836108a9565b810190611120565b905f6113e1565b503d611435565b611115565b50505050611250611243610a4b936113f3565b8061147b5f611481936108a9565b80610119565b5f61134a565b5050505050505050600190565b929161149f91611ef7565b9060e08201916115086111f76114dc6114be865165ffffffffffff1690565b61010085019765ffffffffffff806111748b5165ffffffffffff1690565b936040840151906114fd6060860151926111e36111b6602089015160ff1690565b608085015190611c74565b61154557611524918160a060c06111f794015191015190611dec565b61153e57611250611243610a4b935165ffffffffffff1690565b5050600190565b50505050600190565b9091823591602084013592604085013594606081013501926115a484359183610f606115938560051b89019765ffffffffffff8c169065ffffffffffff8c1690611cdf565b963690604060208201359101610ab7565b156115eb576115c0936115bb916020369201610fcb565b611dec565b1561153e57610a4b91906001600160d01b031965ffffffffffff60a01b9160d01b169160a01b161790565b505050505050600190565b9182828101601f19013561649261ffff30801c190402146116145750565b604091935080925001350160208135910191565b9291908215611755575b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a060208301351161172d576001600160a01b035f94166dd9ecebf3c23529de49815dac1c4c8114908115611723575b81156116f3575b506116d3575b83156116c0575b83156116ae575b505050155f03631626ba7e1760e01b90565b6116b89350612567565b5f808061169c565b92506116cd828285612296565b92611695565b92506116ed6116e133610d48565b84610f60368686610ab7565b9261168e565b90505f52600260205261171a3360405f20906001600160a01b03165f5260205260405f2090565b5415155f611688565b3381149150611681565b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b61773961ffff84190402810361163257505050507f773900010000000000000000000000000000000000000000000000000000000090565b6001906117b4935f520160205260405f20906001600160a01b03165f5260205260405f2090565b54151590565b815f52600180016020526117e28160405f20906001600160a01b03165f5260205260405f2090565b5461183b5780611835915f52600160205260405f20600181540190848260051b82015555805f52600160205260405f2054925f52600260205260405f20906001600160a01b03165f5260205260405f2090565b55600190565b50505f90565b9061184d83828461178d565b61189a575f81815260208390526040902080546001908101600581901b830186905591829055611835939091945f520160205260405f20906001600160a01b03165f5260205260405f2090565b5050505f90565b5f1981146105535760010190565b5f1981019190821161055357565b60051981019190821161055357565b60221981019190821161055357565b601f1981019190821161055357565b60bf1981019190821161055357565b607f1981019190821161055357565b602003906020821161055357565b9190820391821161055357565b91909161012081840312610123576119396108db565b92611943826101bd565b84526020820135602085015260408201356040850152606082013560608501526080820135608085015261197960a08301610fa8565b60a085015260c082013560c085015260e082013560e085015261010082013567ffffffffffffffff8111610123576119b19201611017565b610100830152565b35610a4b81610f9d565b903590601e1981360301821215610123570180359067ffffffffffffffff821161012357602001918160051b3603831361012357565b919250611a786111f76020850193611a1a611a143687611923565b8261261a565b61010087013591611a7360e0890135611a65611a3860c08c016119b9565b6040519687936020850191926041936001600160f81b0319928452602084015260f81b1660408201520190565b03601f1981018552846108a9565b611c74565b61189a5760a06115bb84611a976111f795610120611aa49801906119c3565b9390910135923691610fcb565b611aad57600190565b5f90565b611ab96126a1565b50611ac48484611ea7565b3560f81c92611ad2856118af565b611add908683611eb5565b3560f81c611aea81610dd5565b611af390610e02565b611afd9087611916565b611b0890878461099e565b909290611b16368286610ab7565b611b1f906127aa565b91611b29836127d7565b611b3390896128f2565b93888551611b4090612a16565b9360208701978851986040890191825198611b5a9061315f565b9190508a5192519351943690611b6f92610ab7565b611b7895612ac0565b9460600151611b8690612c41565b99611b9092612e9f565b96611b996108eb565b60ff918216815291166020820181905260408201859052606082018390526080820193845260a0820198895260c090910196875260408051602081019590955284019190915260f81b6001600160f81b031916606083015260418252611c006061836108a9565b51611c0a92611c74565b1561189a57611aa4926111f79251905190611dec565b9180359060208101350192611c4b84359183610f608460051b88013690604060208201359101610ab7565b15611c6c57611c62936115bb916020369201610fcb565b15611aad57600190565b505050505f90565b906001600160a01b03929183611c8a84846126e8565b911693168314611cd7576001600160a01b0391611ccd916020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004206126e8565b1614610f78575f90565b505050600190565b9160405191602083019384526040830152606082015260608152611d046080826108a9565b5190206040516020810191825260208152611d206040826108a9565b51902090565b90604060429260c0830151611db06001600160a01b03602086015116610cf46060870151936080880151875195869460208601988991926001600160a01b0360a09497969592978160c08601997f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98752166020860152166040840152606083015260808201520152565b51902091015190604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b929091905f915b8451831015611e3557611e06838661277e565b519081811015611e24575f52602052600160405f205b920191611df3565b905f52602052600160405f20611e1c565b915092501490565b60405190610120820182811067ffffffffffffffff8211176108a4576040525f610100838281528260208201528260408201528260608201528260808201528260a0820152606060c08201528260e08201520152565b634e487b7160e01b5f52603260045260245ffd5b9015611eb05790565b611e93565b90821015611eb0570190565b919091356001600160d01b031981169260068110611edd575050565b6001600160d01b0319929350829060060360031b1b161690565b611eff611e3d565b50611f0a8282611ea7565b3560f81c91600c91611f1c8383611916565b611f25836118bd565b611f309184846109ba565b611f3991611ec1565b60d01c9180611f47816118bd565b90611f539181856109ba565b611f5c91611ec1565b60d01c93611f6a8183611916565b611f73906118af565b611f7e908385611eb5565b3560f81c90611f8c82610dd5565b611f9590610e02565b90611f9f91610e2c565b611fa99083611916565b611fb490838561099e565b9390611fc1368683610ab7565b611fca906127aa565b91611fd4836127d7565b611fde908a6128f2565b93898551611feb90612a16565b97602087019485519560408901918251986120059061315f565b9190508a519251935194369061201a92610ab7565b61202395612ac0565b946060015161203190612c41565b9561203b92612d4e565b946120446108db565b60ff909916895260ff16602089015260408801526060870152608086015260a085015260c084015265ffffffffffff1660e083015265ffffffffffff1661010082015290565b90805f5260026020526120b18260405f20906001600160a01b03165f5260205260405f2090565b5491821561189a575f19830191838311610553575f828152600160205260409020545f19810191908211610553575f94848484612110956118359803612126575b509050612101915060016134a7565b6002905f5260205260405f2090565b906001600160a01b03165f5260205260405f2090565b6121469261210161213c6121109385600161345a565b8092856001613489565b555f8084816120f2565b81601f820112156101235780519061216782610918565b9261217560405194856108a9565b8284526020838301011161012357815f9260208093018386015e8301015290565b51906101c8826101ac565b9080601f830112156101235781516121b881610fb3565b926121c660405194856108a9565b81845260208085019260051b82010192831161012357602001905b8282106121ee5750505090565b81518152602091820191016121e1565b9060e0828203126101235781516001600160f81b0319811681036101235792602083015167ffffffffffffffff8111610123578261223d918501612150565b92604081015167ffffffffffffffff8111610123578361225e918301612150565b9260608201519261227160808401612196565b9260a08101519260c082015167ffffffffffffffff811161012357610a4b92016121a1565b90923093306124bf575b60405190600119858201013560f01c94600e830196869187810384016041198101976119015f5260408960203789158a604201841017816042601e20181761247f57507f5479706564446174615369676e2800000000000000000000000000000000000086526001198101999889818c82378188016028600e8201526029600d8201515f1a03612429575b506f07fffffe000000000000010000000000919250999899515f1a1c5b88515f1a602881146123695790651201000000016001921c17980197612348565b50929496999086986040610a4b9b83605c96989a957f20636f6e74656e74732c737472696e67206e616d652c737472696e670000000085527f2076657273696f6e2c75696e7432353620636861696e49642c61646472657373601c8601527f20766572696679696e67436f6e74726163742c627974657333322073616c7429603c8601528785013788370103018620835260e08320604052600116604201601e2092604119910301935b604052612dcb576124249033612ddc565b612dcb565b60015f5b016029600d82840301515f1a14848210111561244b5760019061242d565b6028915080806040600e936f07fffffe000000000000010000000000970397886041199101010185378a010153829161232b565b949699505095505050610a4b94505f907f983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de5f5260205260405f2091612413565b6040516342580cb760e11b815294505f85600481335afa8015611455575f955f5f905f925f9461252e575b50906001600160a01b039291604051996020815191012060408b01526020815191012060608a015260808901521660a087015260c086015260e085016040526122a0565b925050506001600160a01b03965061255891503d805f833e61255081836108a9565b8101906121fe565b509399939450929091906124ea565b92915f933a1561257657505050565b90919293503a3a5260203a3a386d378edcd5b5b0a24f5342d8c1048561fffffa503a51156125b7575b610f60610a4b936125af33610d48565b933691610ab7565b60405192631626ba7e3a526d378edcd5b5b0a24f5342d8c1048560205260408052454561ffff011790815a106d378edcd5b5b0a24f5342d8c1048584141761261857610a4b94610f60923a906064601c3a923090fa5060405293505061259f565bfe5b9060206042926080830151611db06001600160a01b03855116610cf46040870151936060880151604051958694898601988991926001600160a01b0360a09497969592978160c08601997f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98752166020860152166040840152606083015260808201520152565b6040519060e0820182811067ffffffffffffffff8211176108a457604052606060c0835f81525f60208201525f60408201525f838201525f60808201525f60a08201520152565b9190915f92604051918151806040146127405760411461270757505050565b602092945060608201515f1a835260408201516060525b5f5201516040526020604060805f60015afa505f6060523d6060185191604052565b5060209294507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040830151601b8160ff1c0185521660605261271e565b8051821015611eb05760209160051b010190565b6040519061279f82610888565b5f6020838281520152565b6127b2612792565b506020815191604051926127c584610888565b835201602082015290565b1561012357565b906127e182612f08565b15610123576127ef82612f28565b916127f983610fb3565b9061280760405192836108a9565b838252601f1961281685610fb3565b015f5b8181106128a65750506020810161283a815161283481612f89565b90610e2c565b945f905b808210612860575050610a4b929394612858915190611916565b9051146127d0565b909561289e81612871600193612ff4565b9061287a6108fa565b82815281602082015261288d8b8a61277e565b526128988a8961277e565b50610e2c565b96019061283e565b6020906128b1612792565b82828701015201612819565b604051906080820182811067ffffffffffffffff8211176108a457604052606080835f81525f60208201525f60408201520152565b60ff906128fd6128bd565b5016806129775750600560069061295961295360079460ff61294b612935826129436129358261293b6129358260089e5b168a61277e565b51613072565b9c168761277e565b98168461277e565b94169061277e565b51613123565b91612962610909565b93845260208401526040830152606082015290565b6002036129ab576007600990612959612953600a9460ff61294b612935826129436129358261293b61293582600b9e61292e565b60405162461bcd60e51b815260206004820152602860248201527f547856616c696461746f724c69623a3a20756e737570706f727465642065766d60448201527f20747820747970650000000000000000000000000000000000000000000000006064820152608490fd5b60258110612a7757612a278161314d565b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116810361055357612a6c612a67610a4b93612a719360011b90611916565b6118cc565b610e10565b60ff1690565b60018111612a7157601b81018091116105535760ff1690565b805191908290602001825e015f815290565b6001906001600160f81b0319610a4b949360f81b1681520190612a90565b94612b1a9192612b10612b08612afc612b1f94612af5612ae9612aee612ae9612b259c9d613634565b6136b0565b5192613634565b5190610e2c565b612af5612ae98a613634565b918551611916565b9283918551611916565b611916565b91613290565b9060ff831660028103612b5d575050611d20612b4c610cf492612b46610934565b90613316565b604051928391602083019586612aa2565b91925090612bd75760258110612bca57612bc091612bbb612b88612b83612bb59461314d565b61318b565b6111e3612b96612ae961358f565b612bb5612ba4612ae961358f565b916040519788956020870190612a90565b90612a90565b613316565b6020815191012090565b50612bc090612b46610934565b60405162461bcd60e51b8152602060048201526024808201527f547856616c696461746f724c69623a3a20756e737570706f727465642074782060448201527f74797065000000000000000000000000000000000000000000000000000000006064820152608490fd5b6020815110612c83578051601f19810190811161055357612c619161322d565b602081519101519060208110612c75575090565b5f199060200360031b1b1690565b608460405162461bcd60e51b815260206004820152602560248201527f54784465636f6465723a3a2063616c6c44617461206c656e67746820746f6f2060448201527f73686f72740000000000000000000000000000000000000000000000000000006064820152fd5b90612cf782610fb3565b612d0460405191826108a9565b8281528092612d15601f1991610fb3565b0190602036910137565b60ff168015610553575f190190565b359060208110612c75575090565b60ff5f199116019060ff821161055357565b929190612d5d60ff8316612ced565b93600b198201828111610553575f198101908111610553579291925b60ff8316612d875750505050565b612dbf81612dab612da582612d9e612dc5966118db565b89886109ba565b90612d2e565b612db960ff61292e88612d3c565b526118db565b92612d1f565b91612d79565b610f60610a4b93926125af33610d48565b5f6001600160a01b03916004604051809481936342580cb760e11b8352165afa9081156114555760a0915f915f5f915f93612e7a575b50604051937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f855260208151910120602085015260208151910120604084015260608301526080820152206719010000000000005f52601a52603a526042601820905f603a52565b92505050612e9291503d805f833e61255081836108a9565b509394509250905f612e12565b9291612ead60ff8216612ced565b935f198301838111610553575b60ff8316612ec85750505050565b601f19810181811161055357612ee6612da5612f02938388876109ba565b612efb60ff612ef487612d3c565b168961277e565b5292612d1f565b91612eba565b805115612f2357602060c0910151515f1a10611aad57600190565b505f90565b805115612f23575f9060208101908151612f4181612f89565b8101809111610553579151905181018091116105535791905b828110612f675750905090565b612f7081612ff4565b810180911161055357612f8390916118a1565b90612f5a565b515f1a6080811015612f9a57505f90565b60b881108015612fde575b15612fb05750600190565b60c0811015612fcf57610a4b90612fca9060b75b90611916565b610e02565b610a4b90612fca9060f7612fc4565b5060c08110158015612fa5575060f88110612fa5565b80515f1a906080821015613009575050600190565b60b882101561301f5750612fca610a4b916118f9565b60c08210156130425760010151602082900360b7016101000a90040160b5190190565b60f88210156130585750612fca610a4b916118ea565b60010151602082900360f7016101000a90040160f5190190565b805180151590816130a8575b50156101235761308d9061315f565b9051906020811061309c575090565b6020036101000a900490565b6021915011155f61307e565b604080519091906130c583826108a9565b60208152918290601f190190369060200137565b604080519091906130ea83826108a9565b6001815291601f1901366020840137565b9061310582610918565b61311260405191826108a9565b8281528092612d15601f1991610918565b80511561012357613136610a4b9161315f565b613142819392936130fb565b9283602001906134fe565b60221981019081116105535760011c90565b90602082019161316f8351612f89565b9251908382018092116105535751928303928311610553579190565b612ae9610a4b91613634565b1561319e57565b606460405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152fd5b156131e957565b606460405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152fd5b906132386001613197565b815160208201808311610553576132509110156131e2565b6040519160208084019260408501920101905b80831061327d57505060208252601f01601f191660405290565b9091602080918451815201920190613263565b916132a081601f81011015613197565b6132b683516132af8385610e2c565b11156131e2565b806132ce575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b8084106133035750508252601f01601f191660405290565b90926020809185518152019301906132eb565b61333190610cf4612bb5936040519485936020850190612a90565b805190603882101561338557612bb591610cf4610a4b926001600160f81b031961336460c061335e6130d9565b95610e2c565b60f81b165f1a61337384613571565b535b6040519485936020850190612a90565b916001915f5b6133958483610db7565b156133b2576133a66133ac916118a1565b93610deb565b9261338b565b9092509290926133c96133c482610e02565b6130fb565b926001600160f81b03196133e66133e160c085610e2c565b610e1e565b60f81b165f1a6133f585613571565b5360015b8281111561341457505050612bb591610cf4610a4b92613375565b806001600160f81b031961343f612a716134396134346134559689611916565b6134ef565b86610db7565b60f81b165f1a61344f828861357e565b536118a1565b6133f9565b905f5260205260405f209081548110156134795760010160051b015490565b638277484f5f526020526024601cfd5b905f5260205260405f209081548110156134795760010160051b0155565b905f5260205260405f2080549081156134eb575f198201918083116105535781548310156134da575f9060051b82015555565b82638277484f5f526020526024601cfd5b5050565b601f8111610553576101000a90565b9091801561356c575b602081101561353c578061351a57505050565b61352961343461352e92611908565b6118af565b905182518216911916179052565b919080518252602081018091116105535790602081018091116105535791601f1981019081111561350757610da3565b505050565b805115611eb05760200190565b908151811015611eb0570160200190565b6135976130b4565b905f60208301525f915b60208310613603575b6135b66133c484611908565b905f5b82518110156135fc576001906135e96135db6135d4886118a1565b978561357e565b516001600160f81b03191690565b5f1a6135f5828661357e565b53016135b9565b5090925050565b916136216136146135db838661357e565b6001600160f81b03191690565b61362e57600101916135a1565b916135aa565b9061363d6130b4565b9160208301525f915b6020831061368c575b61365b6133c484611908565b905f5b82518110156135fc576001906136796135db6135d4886118a1565b5f1a613685828661357e565b530161365e565b9161369d6136146135db838661357e565b6136aa5760010191613646565b9161364f565b805160018114908161374a575b50156136c65790565b6136d08151613762565b6040519181518084526020840190840191602083019160208501905b83811061373a5750508051809286518201875293019260208085019201905b82811061372a5750509251603f91011590910101601f19166040525090565b815181526020918201910161370b565b81518152602091820191016136ec565b905015611eb0576080602082015160f81c105f6136bd565b603881101561379a576001600160f81b031961378760806137816130d9565b93610e2c565b60f81b165f1a61379682613571565b5390565b6001915f5b6137a98484610db7565b156137c0576133a66137ba916118a1565b9261379f565b9092506137cf6133c482610e02565b916001600160f81b03196137e76133e1608085610e2c565b60f81b165f1a6137f684613571565b5360015b828111156138085750505090565b806001600160f81b0319613828612a716134396134346138389689611916565b60f81b165f1a61344f828761357e565b6137fa56fea164736f6c634300081b000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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