Contract

0x068EA3E30788ABaFDC6fD0b38d20BD38a40a2B3D

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
14550782024-12-24 11:18:013 days ago1735039081  Contract Creation0 S
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
File 1 of 25 : K1MeeValidator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

import {IValidator, MODULE_TYPE_VALIDATOR} from "../interfaces/IERC7579Module.sol";
import {ERC7739Validator} from "erc7739Validator/ERC7739Validator.sol";

// Fusion libraries - validate userOp using on-chain tx or off-chain permit
import {EnumerableSet} from "../libraries/storage/EnumerableSet4337.sol";
import "../libraries/SuperTxEcdsaValidatorLib.sol";

contract K1MeeValidator is IValidator, ERC7739Validator {
    // using SignatureCheckerLib for address;
    using EnumerableSet for EnumerableSet.AddressSet;

    /*//////////////////////////////////////////////////////////////////////////
                            CONSTANTS & STORAGE
    //////////////////////////////////////////////////////////////////////////*/

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

    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 NewOwnerIsContract();

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

    /*//////////////////////////////////////////////////////////////////////////
                                     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());
        require(!_isContract(newOwner), NewOwnerIsContract());
        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());
        require(!_isContract(newOwner), NewOwnerIsContract());
        smartAccountOwners[msg.sender] = newOwner;
    }

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

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

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

    /**
     * Validates PackedUserOperation
     *
     * @param userOp UserOperation to be validated
     * @param userOpHash Hash of the UserOperation to be validated
     *
     * @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 = smartAccountOwners[userOp.sender];
        return SuperTxEcdsaValidatorLib.validateUserOp(userOp, userOpHash, 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)
    {
        return _erc1271IsValidSignatureWithSender(sender, hash, _erc1271UnwrapSignature(signature));
    }

    /// @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
        pure
        returns (bool validSig)
    {
        require(data.length == 20, InvalidDataLength());
        address owner = address(bytes20(data[0:20]));
        return _validateSignatureForOwner(owner, hash, sig);
    }

    /*//////////////////////////////////////////////////////////////////////////
                                     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
    function version() external pure returns (string memory) {
        return "1.0.0";
    }

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

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

    /// @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 _validateSignatureForOwner(smartAccountOwners[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
    }

    /// @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
        pure
        returns (bool)
    {
        return SuperTxEcdsaValidatorLib.validateSignatureForOwner(owner, hash, signature);
    }

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

    /// @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 Checks if the address is a contract
    /// @param account The address to check
    /// @return True if the address is a contract, false otherwise
    function _isContract(address account) private view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
}

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

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;

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

File 3 of 25 : ERC7739Validator.sol
// 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 4 of 25 : EnumerableSet4337.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

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

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

File 5 of 25 : SuperTxEcdsaValidatorLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.27;

import "account-abstraction/interfaces/PackedUserOperation.sol";
import "./fusion/PermitValidatorLib.sol";
import "./fusion/TxValidatorLib.sol";
import "./fusion/EcdsaValidatorLib.sol";
import "./fusion/UserOpValidatorLib.sol";
import "./util/BytesLib.sol";

library SuperTxEcdsaValidatorLib {
    using BytesLib for bytes;

    enum SuperSignatureType {
        OFF_CHAIN,
        ON_CHAIN,
        ERC20_PERMIT,
        USEROP
    }

    uint8 constant SIG_TYPE_OFF_CHAIN = 0x00;
    uint8 constant SIG_TYPE_ON_CHAIN = 0x01;
    uint8 constant SIG_TYPE_ERC20_PERMIT = 0x02;
    // ...leave space for other sig types: ERC-7683, Permit2, etc
    uint8 constant SIG_TYPE_USEROP = 0xff;

    struct SuperSignature {
        SuperSignatureType signatureType;
        bytes signature;
    }

    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, address owner)
        internal
        returns (uint256)
    {
        SuperSignature memory decodedSig = decodeSignature(userOp.signature);

        if (decodedSig.signatureType == SuperSignatureType.OFF_CHAIN) {
            return EcdsaValidatorLib.validateUserOp(userOp, decodedSig.signature, owner);
        } else if (decodedSig.signatureType == SuperSignatureType.ON_CHAIN) {
            return TxValidatorLib.validateUserOp(userOp, decodedSig.signature, owner);
        } else if (decodedSig.signatureType == SuperSignatureType.ERC20_PERMIT) {
            return PermitValidatorLib.validateUserOp(userOp, decodedSig.signature, owner);
        } else if (decodedSig.signatureType == SuperSignatureType.USEROP) {
            return UserOpValidatorLib.validateUserOp(userOpHash, decodedSig.signature, owner);
        } else {
            revert("SuperTxEcdsaValidatorLib:: invalid userOp sig type");
        }
    }

    function validateSignatureForOwner(address owner, bytes32 hash, bytes memory signature)
        internal
        pure
        returns (bool)
    {
        SuperSignature memory decodedSig = decodeSignature(signature);

        if (decodedSig.signatureType == SuperSignatureType.OFF_CHAIN) {
            return EcdsaValidatorLib.validateSignatureForOwner(owner, hash, decodedSig.signature);
        } else if (decodedSig.signatureType == SuperSignatureType.ON_CHAIN) {
            return TxValidatorLib.validateSignatureForOwner(owner, hash, decodedSig.signature);
        } else if (decodedSig.signatureType == SuperSignatureType.ERC20_PERMIT) {
            return PermitValidatorLib.validateSignatureForOwner(owner, hash, decodedSig.signature);
        } else if (decodedSig.signatureType == SuperSignatureType.USEROP) {
            return UserOpValidatorLib.validateSignatureForOwner(owner, hash, decodedSig.signature);
        } else {
            revert("SuperTxEcdsaValidatorLib:: invalid userOp sig type");
        }
    }

    function decodeSignature(bytes memory self) internal pure returns (SuperSignature memory) {
        bytes memory sig = self.slice(1, self.length - 1);
        if (uint8(self[0]) == SIG_TYPE_OFF_CHAIN) {
            return SuperSignature(SuperSignatureType.OFF_CHAIN, sig);
        } else if (uint8(self[0]) == SIG_TYPE_ON_CHAIN) {
            return SuperSignature(SuperSignatureType.ON_CHAIN, sig);
        } else if (uint8(self[0]) == SIG_TYPE_ERC20_PERMIT) {
            return SuperSignature(SuperSignatureType.ERC20_PERMIT, sig);
        } else if (uint8(self[0]) == SIG_TYPE_USEROP) {
            return SuperSignature(SuperSignatureType.USEROP, sig);
        } else {
            revert(
                "SuperTxEcdsaValidatorLib:: invalid sig type. Expected prefix 0x00 for off-chain, 0x01 for on-chain or 0x02 for erc20 permit itx hash signature or 0xff for normal userOp signature."
            );
        }
    }
}

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

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

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

library AssociatedArrayLib {
    using AssociatedArrayLib for *;

    struct Array {
        uint256 _spacer;
    }

    struct Bytes32Array {
        Array _inner;
    }

    struct AddressArray {
        Array _inner;
    }

    struct UintArray {
        Array _inner;
    }

    error AssociatedArray_OutOfBounds(uint256 index);

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

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

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

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

    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 _slot(Array storage s, address account) private pure returns (bytes32 __slot) {
        assembly {
            mstore(0x00, account)
            mstore(0x20, s.slot)
            __slot := keccak256(0x00, 0x40)
        }
    }
}

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

import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import "openzeppelin/utils/cryptography/MerkleProof.sol";
import "account-abstraction/interfaces/PackedUserOperation.sol";
import "account-abstraction/core/Helpers.sol";
import "../../interfaces/IERC20Permit.sol";
import "../util/EcdsaLib.sol";
import "../util/UserOpLib.sol";

library PermitValidatorLib {
    uint8 constant EIP_155_MIN_V_VALUE = 37;

    using MessageHashUtils for bytes32;

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

    /**
     * This function parses the given userOpSignature into a DecodedErc20PermitSig data structure.
     *
     * Once parsed, the function will check for two conditions:
     *      1. is the expected hash found in the signed Permit message's deadline field?
     *      2. is the recovered message signer equal to the expected signer?
     *
     * If both conditions are met - outside contract can be sure that the expected signer has indeed
     * approved the given hash by signing a given Permit message.
     *
     * 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. extracted hash wasn't equal to the provided expected hash
     *    3. recovered Permit message signer wasn't equal to the expected signer
     *
     * Returns true if the expected signer did indeed approve the given expectedHash by signing an on-chain transaction.
     * In that case, 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 userOp UserOp 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(PackedUserOperation calldata userOp, bytes memory parsedSignature, address expectedSigner)
        internal
        returns (uint256)
    {
        DecodedErc20PermitSig memory decodedSig = abi.decode(parsedSignature, (DecodedErc20PermitSig));

        bytes32 userOpHash =
            UserOpLib.getUserOpHash(userOp, decodedSig.lowerBoundTimestamp, decodedSig.upperBoundTimestamp);

        uint8 vAdjusted = _adjustV(decodedSig.v);
        uint256 deadline = uint256(decodedSig.appendedHash);

        bytes32 structHash = keccak256(
            abi.encode(
                decodedSig.permitTypehash,
                expectedSigner,
                decodedSig.spender,
                decodedSig.amount,
                decodedSig.nonce,
                deadline
            )
        );

        bytes32 signedDataHash = _hashTypedDataV4(structHash, decodedSig.domainSeparator);
        bytes memory signature = abi.encodePacked(decodedSig.r, decodedSig.s, vAdjusted);

        if (!EcdsaLib.isValidSignature(expectedSigner, signedDataHash, signature)) {
            return SIG_VALIDATION_FAILED;
        }

        if (!MerkleProof.verify(decodedSig.proof, decodedSig.appendedHash, userOpHash)) {
            return SIG_VALIDATION_FAILED;
        }

        if (decodedSig.isPermitTx) {
            decodedSig.token.permit(
                expectedSigner, userOp.sender, decodedSig.amount, deadline, vAdjusted, decodedSig.r, decodedSig.s
            );
        }

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

    function validateSignatureForOwner(address expectedSigner, bytes32 hash, bytes memory parsedSignature)
        internal
        pure
        returns (bool)
    {
        DecodedErc20PermitSig memory decodedSig = abi.decode(parsedSignature, (DecodedErc20PermitSig));

        uint8 vAdjusted = _adjustV(decodedSig.v);
        uint256 deadline = uint256(decodedSig.appendedHash);

        bytes32 structHash = keccak256(
            abi.encode(
                decodedSig.permitTypehash,
                expectedSigner,
                decodedSig.spender,
                decodedSig.amount,
                decodedSig.nonce,
                deadline
            )
        );

        bytes32 signedDataHash = _hashTypedDataV4(structHash, decodedSig.domainSeparator);
        bytes memory signature = abi.encodePacked(decodedSig.r, decodedSig.s, vAdjusted);

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

        if (!MerkleProof.verify(decodedSig.proof, decodedSig.appendedHash, hash)) {
            return false;
        }

        return true;
    }

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

    function _adjustV(uint256 v) private 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) private pure returns (uint256 chainId) {
        chainId = (v - 35) / 2;
    }
}

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

import "openzeppelin/utils/cryptography/MerkleProof.sol";
import "account-abstraction/interfaces/PackedUserOperation.sol";
import "account-abstraction/core/Helpers.sol";
import "../rlp/RLPDecoder.sol";
import "../rlp/RLPEncoder.sol";
import "../util/BytesLib.sol";
import "../util/UserOpLib.sol";
import "../util/EcdsaLib.sol";

library TxValidatorLib {
    uint8 constant LEGACY_TX_TYPE = 0x00;
    uint8 constant EIP1559_TX_TYPE = 0x02;

    uint8 constant RLP_ENCODED_R_S_BYTE_SIZE = 66; // 2 * 33bytes (for r, s components)
    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;
    }

    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 expected hash found in the tx.data as the last 32bytes?
     *      2. is the recovered tx signer equal to the expected signer?
     *      2. 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
     *
     * Returns true if the expected signer did indeed approve the given expectedHash by signing an on-chain transaction.
     *
     * @param userOp UserOp being validated.
     * @param parsedSignature Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
     *                        Expecting to receive fully signed serialized EVM transcaction 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 userOp and the EVM transaction.
     */
    function validateUserOp(PackedUserOperation calldata userOp, bytes memory parsedSignature, address expectedSigner)
        internal
        view
        returns (uint256)
    {
        TxData memory decodedTx = decodeTx(parsedSignature);

        bytes32 userOpHash =
            UserOpLib.getUserOpHash(userOp, 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, userOpHash)) {
            return SIG_VALIDATION_FAILED;
        }

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

    function validateSignatureForOwner(address expectedSigner, bytes32 hash, bytes memory parsedSignature)
        internal
        pure
        returns (bool)
    {
        TxData memory decodedTx = decodeTx(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, hash)) {
            return false;
        }

        return true;
    }

    function decodeTx(bytes memory self) internal pure returns (TxData memory) {
        uint8 txType = uint8(self[0]); //first byte is tx type
        uint48 lowerBoundTimestamp =
            uint48(bytes6((self.slice(self.length - 2 * TIMESTAMP_BYTE_SIZE, TIMESTAMP_BYTE_SIZE))));
        uint48 upperBoundTimestamp = uint48(bytes6(self.slice(self.length - TIMESTAMP_BYTE_SIZE, 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 memory rlpEncodedTx = self.slice(1, self.length - appendedDataLen - 1);
        RLPDecoder.RLPItem memory parsedRlpEncodedTx = rlpEncodedTx.toRlpItem();
        RLPDecoder.RLPItem[] memory parsedRlpEncodedTxItems = parsedRlpEncodedTx.toList();
        TxParams memory params = extractParams(txType, parsedRlpEncodedTxItems);

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

    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 memory 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.slice(pos - PROOF_ITEM_BYTE_SIZE, PROOF_ITEM_BYTE_SIZE));
        }
    }

    function calculateUnsignedTxHash(uint8 txType, bytes memory rlpEncodedTx, uint256 rlpEncodedTxPayloadLen, uint256 v)
        private
        pure
        returns (bytes32 hash)
    {
        uint256 totalSignatureSize = RLP_ENCODED_R_S_BYTE_SIZE + 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;
    }
}

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

import "openzeppelin/utils/cryptography/MerkleProof.sol";
import "account-abstraction/interfaces/PackedUserOperation.sol";
import "account-abstraction/core/Helpers.sol";
import "../util/EcdsaLib.sol";
import "../util/UserOpLib.sol";

library EcdsaValidatorLib {
    /**
     * 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
     *
     * 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 userOp UserOp 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(PackedUserOperation calldata userOp, bytes memory parsedSignature, address expectedSigner)
        internal
        view
        returns (uint256)
    {
        (
            bytes32 superTxHash,
            bytes32[] memory proof,
            uint48 lowerBoundTimestamp,
            uint48 upperBoundTimestamp,
            bytes memory userEcdsaSignature
        ) = abi.decode(parsedSignature, (bytes32, bytes32[], uint48, uint48, bytes));

        bytes32 calculatedUserOpHash = UserOpLib.getUserOpHash(userOp, lowerBoundTimestamp, upperBoundTimestamp);
        if (!EcdsaLib.isValidSignature(expectedSigner, superTxHash, userEcdsaSignature)) {
            return SIG_VALIDATION_FAILED;
        }

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

        return _packValidationData(false, upperBoundTimestamp, lowerBoundTimestamp);
    }

    function validateSignatureForOwner(address owner, bytes32 hash, bytes memory parsedSignature)
        internal
        pure
        returns (bool)
    {
        (
            bytes32 superTxHash, //super tx hash
            bytes32[] memory proof,
            bytes memory userEcdsaSignature
        ) = abi.decode(parsedSignature, (bytes32, bytes32[], bytes));

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

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

        return true;
    }
}

File 11 of 25 : UserOpValidatorLib.sol
// 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 UserOpValidatorLib {
    /**
     * 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
        pure
        returns (uint256)
    {
        if (!EcdsaLib.isValidSignature(expectedSigner, userOpHash, parsedSignature)) {
            return SIG_VALIDATION_FAILED;
        }
        return SIG_VALIDATION_SUCCESS;
    }

    function validateSignatureForOwner(address expectedSigner, bytes32 hash, bytes memory parsedSignature)
        internal
        pure
        returns (bool)
    {
        return EcdsaLib.isValidSignature(expectedSigner, hash, parsedSignature);
    }
}

File 12 of 25 : BytesLib.sol
// 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.27;

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;
    }
    // 0 1 2 3 4
    // x x x x x

    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
        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;
    }
}

File 13 of 25 : MessageHashUtils.sol
// 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)
        }
    }
}

File 14 of 25 : MerkleProof.sol
// 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)
        }
    }
}

File 15 of 25 : Helpers.sol
// 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;
    }

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

pragma solidity ^0.8.27;

/**
 * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC-20 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);

    function PERMIT_TYPEHASH() external view returns (bytes32);
}

File 17 of 25 : EcdsaLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

library EcdsaLib {
    using MessageHashUtils for bytes32;
    using ECDSA for bytes32;

    function isValidSignature(address expectedSigner, bytes32 hash, bytes memory signature)
        internal
        pure
        returns (bool)
    {
        if (_recoverSigner(hash, signature) == expectedSigner) return true;
        if (_recoverSigner(hash.toEthSignedMessageHash(), signature) == expectedSigner) return true;
        return false;
    }

    function _recoverSigner(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address owner,,) = hash.tryRecover(signature);
        return owner;
    }
}

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

import "account-abstraction/interfaces/PackedUserOperation.sol";
import "account-abstraction/core/UserOperationLib.sol";

library UserOpLib {
    using UserOperationLib for PackedUserOperation;

    /**
     * Calculates userOp hash. Almost works like a regular 4337 userOp hash with few fields added.
     *
     * @param userOp userOp to calculate the hash for
     * @param lowerBoundTimestamp lower bound timestamp set when constructing userOp
     * @param upperBoundTimestamp upper bound timestamp set when constructing userOp
     */
    function getUserOpHash(
        PackedUserOperation calldata userOp,
        uint256 lowerBoundTimestamp,
        uint256 upperBoundTimestamp
    ) internal view returns (bytes32 userOpHash) {
        userOpHash = keccak256(
            bytes.concat(keccak256(abi.encode(userOp.hash(), lowerBoundTimestamp, upperBoundTimestamp, block.chainid)))
        );
    }
}

File 19 of 25 : RLPDecoder.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.27;

library RLPDecoder {
    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;
    }

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

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

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

    /**
     * RLPItem conversions into data types *
     */
    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;
    }

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

File 20 of 25 : RLPEncoder.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.27;

import "../util/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;
    }
}

File 21 of 25 : Strings.sol
// 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));
    }
}

File 22 of 25 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

File 23 of 25 : UserOperationLib.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

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

import "../interfaces/PackedUserOperation.sol";
import {calldataKeccak, min} from "./Helpers.sol";

/**
 * Utility functions helpful when working with UserOperation structs.
 */
library UserOperationLib {

    uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20;
    uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36;
    uint256 public constant PAYMASTER_DATA_OFFSET = 52;
    /**
     * Get sender from user operation data.
     * @param userOp - The user operation data.
     */
    function getSender(
        PackedUserOperation calldata userOp
    ) internal pure returns (address) {
        address data;
        //read sender from userOp, which is first userOp member (saves 800 gas...)
        assembly {
            data := calldataload(userOp)
        }
        return address(uint160(data));
    }

    /**
     * Relayer/block builder might submit the TX with higher priorityFee,
     * but the user should not pay above what he signed for.
     * @param userOp - The user operation data.
     */
    function gasPrice(
        PackedUserOperation calldata userOp
    ) internal view returns (uint256) {
        unchecked {
            (uint256 maxPriorityFeePerGas, uint256 maxFeePerGas) = unpackUints(userOp.gasFees);
            if (maxFeePerGas == maxPriorityFeePerGas) {
                //legacy mode (for networks that don't support basefee opcode)
                return maxFeePerGas;
            }
            return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
        }
    }

    /**
     * Pack the user operation data into bytes for hashing.
     * @param userOp - The user operation data.
     */
    function encode(
        PackedUserOperation calldata userOp
    ) internal pure returns (bytes memory ret) {
        address sender = getSender(userOp);
        uint256 nonce = userOp.nonce;
        bytes32 hashInitCode = calldataKeccak(userOp.initCode);
        bytes32 hashCallData = calldataKeccak(userOp.callData);
        bytes32 accountGasLimits = userOp.accountGasLimits;
        uint256 preVerificationGas = userOp.preVerificationGas;
        bytes32 gasFees = userOp.gasFees;
        bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);

        return abi.encode(
            sender, nonce,
            hashInitCode, hashCallData,
            accountGasLimits, preVerificationGas, gasFees,
            hashPaymasterAndData
        );
    }

    function unpackUints(
        bytes32 packed
    ) internal pure returns (uint256 high128, uint256 low128) {
        return (uint128(bytes16(packed)), uint128(uint256(packed)));
    }

    //unpack just the high 128-bits from a packed value
    function unpackHigh128(bytes32 packed) internal pure returns (uint256) {
        return uint256(packed) >> 128;
    }

    // unpack just the low 128-bits from a packed value
    function unpackLow128(bytes32 packed) internal pure returns (uint256) {
        return uint128(uint256(packed));
    }

    function unpackMaxPriorityFeePerGas(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return unpackHigh128(userOp.gasFees);
    }

    function unpackMaxFeePerGas(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return unpackLow128(userOp.gasFees);
    }

    function unpackVerificationGasLimit(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return unpackHigh128(userOp.accountGasLimits);
    }

    function unpackCallGasLimit(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return unpackLow128(userOp.accountGasLimits);
    }

    function unpackPaymasterVerificationGasLimit(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET]));
    }

    function unpackPostOpGasLimit(PackedUserOperation calldata userOp)
    internal pure returns (uint256) {
        return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]));
    }

    function unpackPaymasterStaticFields(
        bytes calldata paymasterAndData
    ) internal pure returns (address paymaster, uint256 validationGasLimit, uint256 postOpGasLimit) {
        return (
            address(bytes20(paymasterAndData[: PAYMASTER_VALIDATION_GAS_OFFSET])),
            uint128(bytes16(paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET])),
            uint128(bytes16(paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]))
        );
    }

    /**
     * Hash the user operation data.
     * @param userOp - The user operation data.
     */
    function hash(
        PackedUserOperation calldata userOp
    ) internal pure returns (bytes32) {
        return keccak256(encode(userOp));
    }
}

File 24 of 25 : Math.sol
// 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;
    }
}

File 25 of 25 : SignedMath.sol
// 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/",
    "@ERC4337/=node_modules/@ERC4337/",
    "@erc7579/=node_modules/@erc7579/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@prb/=node_modules/@prb/",
    "@prb/math/=node_modules/erc7739-validator-base/node_modules/@prb/math/src/",
    "@rhinestone/=node_modules/@rhinestone/",
    "@safe-global/=node_modules/@safe-global/",
    "@zerodev/=node_modules/@zerodev/",
    "ExcessivelySafeCall/=node_modules/erc7739-validator-base/node_modules/excessively-safe-call/src/",
    "account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/",
    "ds-test/=node_modules/ds-test/",
    "enumerableset4337/=node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/",
    "erc4337-validation/=node_modules/erc7739-validator-base/node_modules/@rhinestone/erc4337-validation/src/",
    "erc7579/=node_modules/erc7579/",
    "erc7739-validator-base/=node_modules/erc7739-validator-base/",
    "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/",
    "safe7579/=node_modules/erc7739-validator-base/node_modules/@rhinestone/safe7579/src/",
    "sentinellist/=node_modules/erc7739-validator-base/node_modules/@rhinestone/sentinellist/src/",
    "solarray/=node_modules/solarray/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"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":"NewOwnerIsContract","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":"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":"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":"pure","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"}]

6080604052348015600e575f5ffd5b5061398f8061001c5f395ff3fe608060405234801561000f575f5ffd5b50600436106100f0575f3560e01c8063940d384011610093578063e824b56811610063578063e824b56814610283578063ecd0596114610296578063f2fde38b146102aa578063f551e2ee146102bd575f5ffd5b8063940d3840146102165780639700320314610229578063d60b347f1461024a578063d620c85a1461025d575f5ffd5b806354fd4d50116100ce57806354fd4d50146101a25780635c81ca68146101db5780636d61fe70146101f05780638a91b0e314610203575f5ffd5b806306fdde03146100f45780630807dbc11461013f5780632e5b63a614610162575b5f5ffd5b60408051808201909152600e81527f4b314d656556616c696461746f7200000000000000000000000000000000000060208201525b6040516101369190612f01565b60405180910390f35b61015261014d366004612f4d565b610301565b6040519015158152602001610136565b61018a610170366004612f84565b5f602081905290815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610136565b60408051808201909152600581527f312e302e300000000000000000000000000000000000000000000000000000006020820152610129565b6101ee6101e9366004612f84565b610317565b005b6101ee6101fe366004612fdd565b610327565b6101ee610211366004612fdd565b61047a565b61015261022436600461301c565b6104af565b61023c610237366004613095565b61051d565b604051908152602001610136565b610152610258366004612f84565b61055f565b7fd620c85a0000000000000000000000000000000000000000000000000000000061023c565b6101ee610291366004612f84565b610582565b6101526102a43660046130dc565b60011490565b6101ee6102b8366004612f84565b61058e565b6102d06102cb3660046130f3565b610629565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610136565b5f61030e60018385610647565b90505b92915050565b6103236001338361067d565b5050565b5f819003610361576040517f1f2a381c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152602081905260409020546001600160a01b0316156103b0576040517fe72ce85e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6103be601482848661314b565b6103c791613172565b60601c905080610403576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803b15610423576040516383e6a1cb60e01b815260040160405180910390fd5b335f908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316179055601482111561047557610475610470836014818761314b565b610692565b505050565b335f818152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19169055610323906001906106f9565b5f601482146104ea576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6104f8601482858761314b565b61050191613172565b60601c905061051281888888610703565b979650505050505050565b5f80808061052e6020870187612f84565b6001600160a01b03908116825260208201929092526040015f2054169050610557848483610744565b949350505050565b6001600160a01b038082165f908152602081905260408120549091161515610311565b610323600133836108b0565b6001600160a01b0381166105ce576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803b156105ee576040516383e6a1cb60e01b815260040160405180910390fd5b335f908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b5f61063e858561063986866108c5565b6108f5565b95945050505050565b6001600160a01b038181165f908152600185016020908152604080832093861683529290529081205415155b90505b9392505050565b5f61067384846001600160a01b0385166109d7565b5f5b61069f6014836131da565b811015610475576106f03384846106b78560146131ed565b906106c3866001613204565b6106ce9060146131ed565b926106db9392919061314b565b6106e491613172565b6001919060601c61067d565b50600101610694565b6103238282610a5c565b5f61063e858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610ab092505050565b5f80610790610757610100870187613217565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610b6092505050565b90505f815160038111156107a6576107a661325a565b036107c2576107ba85826020015185610d7e565b915050610676565b6001815160038111156107d7576107d761325a565b036107eb576107ba85826020015185610e15565b6002815160038111156108005761080061325a565b03610814576107ba85826020015185610ef0565b6003815160038111156108295761082961325a565b0361083d576107ba84826020015185611147565b60405162461bcd60e51b815260206004820152603260248201527f53757065725478456364736156616c696461746f724c69623a3a20696e76616c60448201527f696420757365724f70207369672074797065000000000000000000000000000060648201526084015b60405180910390fd5b5f61067384846001600160a01b038516611168565b818161649261ffff30801c190402818301601f190135036108ee57506040810135016020810190355b9250929050565b5f816109325761773961ffff83190402840361093257507f7739000100000000000000000000000000000000000000000000000000000000610557565b60208301357f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0811115610991576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61099e87878787611246565b806109af57506109af868686611260565b806109c057506109c08686866114fe565b155f03631626ba7e1760e01b979650505050505050565b5f81815260018401602090815260408083206001600160a01b0386168452909152812054610a55575f838152602085815260409091208054600101918202810184905555610a258484611569565b5f8381526001808701602090815260408084206001600160a01b0389168552909152909120919091559050610676565b505f610676565b5f610a67838361157c565b905060015b818111610aaa575f610a888585610a83858761326e565b611587565b9050610a95858583611168565b50508080610aa290613281565b915050610a6c565b50505050565b5f5f610abb83610b60565b90505f81516003811115610ad157610ad161325a565b03610ae5576107ba85858360200151611593565b600181516003811115610afa57610afa61325a565b03610b0e576107ba858583602001516115f2565b600281516003811115610b2357610b2361325a565b03610b37576107ba8585836020015161169a565b600381516003811115610b4c57610b4c61325a565b0361083d576107ba858583602001516117ec565b604080518082019091525f8152606060208201525f610b8f6001808551610b87919061326e565b8591906117f8565b90505f60ff16835f81518110610ba757610ba7613299565b016020015160f81c03610bd05760408051808201909152805f5b81526020019190915292915050565b600160ff16835f81518110610be757610be7613299565b016020015160f81c03610c065760408051808201909152806001610bc1565b600260ff16835f81518110610c1d57610c1d613299565b016020015160f81c03610c3c5760408051808201909152806002610bc1565b60ff8016835f81518110610c5257610c52613299565b016020015160f81c03610c715760408051808201909152806003610bc1565b60405162461bcd60e51b81526020600482015260b360248201527f53757065725478456364736156616c696461746f724c69623a3a20696e76616c60448201527f69642073696720747970652e204578706563746564207072656669782030783060648201527f3020666f72206f66662d636861696e2c203078303120666f72206f6e2d63686160848201527f696e206f72203078303220666f72206572633230207065726d6974206974782060a48201527f68617368207369676e6174757265206f72203078666620666f72206e6f726d6160c48201527f6c20757365724f70207369676e61747572652e0000000000000000000000000060e4820152610104016108a7565b50919050565b5f5f5f5f5f5f87806020019051810190610d989190613430565b945094509450945094505f610dbe8a8565ffffffffffff168565ffffffffffff1661191f565b9050610dcb888784611986565b610dde5760019650505050505050610676565b610de9858783611a0a565b610dfc5760019650505050505050610676565b610e075f8486611a1f565b9a9950505050505050505050565b5f5f610e2084611a55565b90505f610e47868360e0015165ffffffffffff1684610100015165ffffffffffff1661191f565b90505f826040015183606001518460200151604051602001610e8993929190928352602083019190915260f81b6001600160f81b031916604082015260410190565b6040516020818303038152906040529050610ea985846080015183611986565b610eb95760019350505050610676565b610ecc8360c001518460a0015184611a0a565b610edc5760019350505050610676565b6105125f8461010001518560e00151611a1f565b5f5f83806020019051810190610f0691906134d9565b90505f610f2e8683610140015165ffffffffffff1684610160015165ffffffffffff1661191f565b90505f610f3f836101800151611cae565b6101008401516040808601516020808801516080808a015160c0808c01518751958601969096526001600160a01b03808f169786019790975295909216606084015282015260a0810191909152908101829052919250905f9060e0016040516020818303038152906040528051906020012090505f610fc2828760600151611d08565b6101a08701516101c08801516040805160208101939093528201526001600160f81b031960f887901b1660608201529091505f906061016040516020818303038152906040529050611015898383611986565b611029576001975050505050505050610676565b61103e87610120015188610100015188611a0a565b611052576001975050505050505050610676565b8660e00151156111235786516001600160a01b031663d505accf8a61107a60208f018f612f84565b60808b01516101a08c01516101c08d015160405160e087901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03958616600482015294909316602485015260448401919091526064830189905260ff8a16608484015260a483015260c482015260e4015f604051808303815f87803b15801561110c575f5ffd5b505af115801561111e573d5f5f3e3d5ffd5b505050505b6111385f886101600151896101400151611a1f565b9b9a5050505050505050505050565b5f611153828585611986565b61115f57506001610676565b505f9392505050565b5f81815260018401602090815260408083206001600160a01b0386168452909152812054801561123d575f61119e60018361326e565b90505f60016111ad8888611569565b6111b7919061326e565b9050808214611201575f6111cc888884611d47565b90506111da88888584611d53565b5f90815260018801602090815260408083206001600160a01b038a16845290915290208390555b61120b8787611d5f565b5050505f8281526001808601602090815260408084206001600160a01b03881685529091528220919091559050610676565b5f915050610676565b5f61125085611d69565b156105575761063e848484611da9565b5f308015611319575f5f5f5f5f336001600160a01b03166384b0196e6040518163ffffffff1660e01b81526004015f60405180830381865afa1580156112a8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112cf9190810190613601565b506040805186516020978801208183015285519590960194909420606086015260808501929092526001600160a01b031660a084015260c083015260e08201905296505050505050505b6040516002840385013560f01c8060420180860387016119015f52604081602037821582881017896042601e20181715611384575f94507f983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de85528860205260408520985050506114dd565b7f5479706564446174615369676e280000000000000000000000000000000000008452600e84018360408301823760288185019081525f1901515f1a6029146113fd575f6001858301035b6001820191506029828203515f1a14868310116113cf57508085039450808560408501018337602881830153505b6f07fffffe00000000000001000000000081515f1a1c5b602882515f1a1461143a57806512010000000183515f1a1c179050600182019150611414565b7f20636f6e74656e74732c737472696e67206e616d652c737472696e670000000082527f2076657273696f6e2c75696e7432353620636861696e49642c61646472657373601c8301527f20766572696679696e67436f6e74726163742c627974657333322073616c7429603c830152605c820191508460408401833760408388379084018590038520865260e08620604052600116604201601e20985050909403935b50604052806114f3576114f03386611dcd565b94505b61063e858585611da9565b5f3a610676573a3a526d378edcd5b5b0a24f5342d8c1048560203a3a388461fffffa503a5161155d57604051631626ba7e3a528160205260408052454561ffff0117805a10838814171561154e57fe5b3a3a6064601c3085fa50506040525b50610673848484611da9565b5f8181526020839052604081205461030e565b5f61030e8383611569565b5f610673848484611d47565b5f5f5f5f848060200190518101906115ab91906136d4565b9250925092506115bc878483611986565b6115cb575f9350505050610676565b6115d6828488611a0a565b6115e5575f9350505050610676565b5060019695505050505050565b5f5f6115fd83611a55565b90505f81604001518260600151836020015160405160200161163f93929190928352602083019190915260f81b6001600160f81b031916604082015260410190565b604051602081830303815290604052905061165f86836080015183611986565b61166d575f92505050610676565b6116808260c001518360a0015187611a0a565b61168e575f92505050610676565b50600195945050505050565b5f5f828060200190518101906116b091906134d9565b90505f6116c1826101800151611cae565b90505f8261010001515f1c90505f836040015188856020015186608001518760c0015186604051602001611729969594939291909586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b6040516020818303038152906040528051906020012090505f611750828660600151611d08565b6101a08601516101c08701516040805160208101939093528201526001600160f81b031960f887901b1660608201529091505f9060610160405160208183030381529060405290506117a38a8383611986565b6117b5575f9650505050505050610676565b6117ca8661012001518761010001518b611a0a565b6117dc575f9650505050505050610676565b5060019998505050505050505050565b5f610673848484611986565b60608161180681601f613204565b10156118545760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f7700000000000000000000000000000000000060448201526064016108a7565b61185e8284613204565b845110156118ae5760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e647300000000000000000000000000000060448201526064016108a7565b6060821580156118cc5760405191505f825260208201604052611916565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119055780518352602092830192016118ed565b5050858452601f01601f1916604052505b50949350505050565b5f61192984611eb8565b60408051602081019290925281018490526060810183905246608082015260a00160408051601f19818403018152828252805160209182012090830152016040516020818303038152906040528051906020012090509392505050565b5f836001600160a01b031661199b8484611ed0565b6001600160a01b0316036119b157506001610676565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c849052603c90206001600160a01b038516906119f49084611ed0565b6001600160a01b03160361115f57506001610676565b5f82611a168584611ee7565b14949350505050565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b85611a45575f611a48565b60015b60ff161717949350505050565b60408051610120810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e081018290526101008101919091525f825f81518110611aaf57611aaf613299565b016020015160f81c90505f611ae1611ac960066002613742565b60ff168551611ad8919061326e565b859060066117f8565b611aea9061375e565b60d01c90505f611b0d600660ff168651611b04919061326e565b869060066117f8565b611b169061375e565b60d01c90505f856001611b2b60066002613742565b60ff168851611b3a919061326e565b611b44919061326e565b81518110611b5457611b54613299565b016020015160f81c90505f611b6b60066002613742565b60ff16602060ff168360ff16611b8191906131ed565b611b8c906001613204565b611b969190613204565b90505f611bbe600180848b51611bac919061326e565b611bb6919061326e565b8a91906117f8565b90505f611bf1826040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b90505f611bfd82611f29565b90505f611c0a898361202f565b90506040518061012001604052808a60ff168152602001611c2d835f0151611cae565b60ff1681526020018260200151815260200182604001518152602001611c5e8b87611c57886121aa565b86516121b5565b8152602001611c70836060015161234e565b8152602001611c7f8d896123ee565b81526020018965ffffffffffff1681526020018865ffffffffffff168152509950505050505050505050919050565b5f60258210611cec576023611cc2836124cf565b611ccd9060026131ed565b611cd7908461326e565b611ce1919061326e565b61031190601b613204565b60018211611cff5761031182601b613204565b5090565b919050565b6040517f190100000000000000000000000000000000000000000000000000000000000081526002810182905260228101839052604290205f9061030e565b5f6106738484846124e7565b610aaa848484846124fe565b6103238282612516565b5f6dd9ecebf3c23529de49815dac1c4c6001600160a01b0383161480611d9757506001600160a01b03821633145b80610311575061031160013384610647565b335f90815260208190526040812054610673906001600160a01b0316858585610703565b5f5f5f5f5f866001600160a01b03166384b0196e6040518163ffffffff1660e01b81526004015f60405180830381865afa158015611e0d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e349190810190613601565b50509450945094509450506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815284516020860120602082015283516020850120604082015282606082015281608082015260a081209550506719010000000000005f5284601a5285603a52604260182094505f603a525050505092915050565b5f611ec282612552565b805190602001209050919050565b5f80611edc8484612607565b509095945050505050565b5f81815b8451811015611f2157611f1782868381518110611f0a57611f0a613299565b6020026020010151612650565b9150600101611eeb565b509392505050565b6060611f348261267c565b611f3c575f5ffd5b5f611f46836126b3565b90505f8167ffffffffffffffff811115611f6257611f626132ad565b604051908082528060200260200182016040528015611fa657816020015b604080518082019091525f8082526020820152815260200190600190039081611f805790505b5090505f611fb78560200151612736565b8560200151611fc69190613204565b90505f805b8481101561202457611fdc836127af565b915060405180604001604052808381526020018481525084828151811061200557612005613299565b602090810291909101015261201a8284613204565b9250600101611fcb565b509195945050505050565b61205760405180608001604052805f81526020015f81526020015f8152602001606081525090565b5f80808060ff871661207757506005925060069150600790506008612105565b60011960ff88160161209757506007925060099150600a9050600b612105565b60405162461bcd60e51b815260206004820152602860248201527f547856616c696461746f724c69623a3a20756e737570706f727465642065766d60448201527f207478207479706500000000000000000000000000000000000000000000000060648201526084016108a7565b6040518060800160405280612135888660ff168151811061212857612128613299565b6020026020010151612852565b8152602001612152888560ff168151811061212857612128613299565b5f1b8152602001612171888460ff168151811061212857612128613299565b5f1b815260200161219d888760ff168151811061219057612190613299565b602002602001015161289c565b9052979650505050505050565b5f5f6105578361290e565b5f5f6121c083612950565b516121cc906042613204565b90505f8486516121dc919061326e565b90505f6122038283858a516121f1919061326e565b6121fb919061326e565b8991906117f8565b905060011960ff89160161225b578761222a8260405180602001604052805f815250612963565b60405160200161223b9291906137e1565b604051602081830303815290604052805190602001209350505050610557565b60ff88166122e157602585106122c9576122b88161228061227b886124cf565b612950565b6122895f612950565b6122925f612950565b6040516020016122a4939291906137ff565b604051602081830303815290604052612963565b805190602001209350505050610557565b6122b88160405180602001604052805f815250612963565b60405162461bcd60e51b8152602060048201526024808201527f547856616c696461746f724c69623a3a20756e737570706f727465642074782060448201527f747970650000000000000000000000000000000000000000000000000000000060648201526084016108a7565b5f602060ff16825110156123ca5760405162461bcd60e51b815260206004820152602560248201527f54784465636f6465723a3a2063616c6c44617461206c656e67746820746f6f2060448201527f73686f727400000000000000000000000000000000000000000000000000000060648201526084016108a7565b81516123e5906123dc9060209061326e565b839060206117f8565b6103119061381c565b60608160ff1667ffffffffffffffff81111561240c5761240c6132ad565b604051908082528060200260200182016040528015612435578160200160208202803683370190505b5090505f600161244760066002613742565b60ff168551612456919061326e565b612460919061326e565b90505b60ff8316156124c85761248361247a60208361326e565b859060206117f8565b61248c9061381c565b8261249860018661383f565b60ff16815181106124ab576124ab613299565b6020908102919091010152826124c081613858565b935050612463565b5092915050565b5f60026124dd60238461326e565b61031191906131da565b5f82815260208490526040812061067390836129c3565b5f838152602085905260409020610aaa9083836129e9565b5f818152602083905260408120805490918190036125345750505050565b6125498261254360018461326e565b5f6129e9565b5f190190555050565b6060813560208301355f61257161256c6040870187613217565b612a12565b90505f61258461256c6060880188613217565b9050608086013560a087013560c08801355f6125a661256c60e08c018c613217565b604080516001600160a01b039a909a1660208b015289810198909852606089019690965250608087019390935260a086019190915260c085015260e08401526101008084019190915281518084039091018152610120909201905292915050565b5f5f5f835160410361263e576020840151604085015160608601515f1a61263088828585612a24565b955095509550505050612649565b505081515f91506002905b9250925092565b5f81831061266a575f82815260208490526040902061030e565b5f83815260208390526040902061030e565b80515f90810361268d57505f919050565b602082015180515f1a9060c08210156126a957505f9392505050565b5060019392505050565b80515f9081036126c457505f919050565b5f5f90505f6126d68460200151612736565b84602001516126e59190613204565b90505f845f015185602001516126fb9190613204565b90505b8082101561272d5761270f826127af565b6127199083613204565b91508261272581613281565b9350506126fe565b50909392505050565b80515f90811a608081101561274d57505f92915050565b60b8811080612768575060c08110801590612768575060f881105b156127765750600192915050565b60c08110156127a35761278b600160b861383f565b6127989060ff168261326e565b610676906001613204565b61278b600160f861383f565b80515f908190811a60808110156127c957600191506124c8565b60b88110156127ef576127dd60808261326e565b6127e8906001613204565b91506124c8565b60c081101561281c5760b78103600185019450806020036101000a855104600182018101935050506124c8565b60f8811015612830576127dd60c08261326e565b60019390930151602084900360f7016101000a900490920160f5190192915050565b80515f901580159061286657508151602110155b61286e575f5ffd5b5f5f6128798461290e565b8151919350915060208210156105575760208290036101000a9004949350505050565b80516060906128a9575f5ffd5b5f5f6128b48461290e565b915091505f8167ffffffffffffffff8111156128d2576128d26132ad565b6040519080825280601f01601f1916602001820160405280156128fc576020820181803683370190505b50905060208101611916848285612aec565b5f5f5f61291e8460200151612736565b90505f8185602001516129319190613204565b90505f82865f0151612943919061326e565b9196919550909350505050565b606061031161295e83612b6c565b612c84565b60605f8383604051602001612979929190613873565b60408051601f1981840301815291905280519091506129999060c0612cd3565b816040516020016129ab929190613873565b60405160208183030381529060405291505092915050565b5f825482106129dd57638277484f5f52816020526024601cfd5b50600101602002015490565b82548210612a0257638277484f5f52816020526024601cfd5b8060018301602002840155505050565b5f604051828085833790209392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612a5d57505f91506003905082612ae2565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015612aae573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116612ad957505f925060019150829050612ae2565b92505f91508190505b9450945094915050565b805f03612af857505050565b60208110612b305782518252612b0f602084613204565b9250612b1c602083613204565b9150612b2960208261326e565b9050612af8565b8015610475575f6001612b4483602061326e565b612b5090610100613964565b612b5a919061326e565b84518451821691191617835250505050565b6040805160208082528183019092526060915f91906020820181803683375050506020810184905290505f5b6020811015612bd057818181518110612bb357612bb3613299565b01602001516001600160f81b0319165f03612bd057600101612b98565b5f612bdc82602061326e565b67ffffffffffffffff811115612bf457612bf46132ad565b6040519080825280601f01601f191660200182016040528015612c1e576020820181803683370190505b5090505f5b8151811015611916578383612c3781613281565b945081518110612c4957612c49613299565b602001015160f81c60f81b828281518110612c6657612c66613299565b60200101906001600160f81b03191690815f1a905350600101612c23565b60608082516001148015612cb157506080835f81518110612ca757612ca7613299565b016020015160f81c105b15612cbd575081610311565b61030e83612ccd85516080612cd3565b90612e84565b6060806038841015612d3b5760408051600180825281830190925290602082018180368337019050509050612d088385613204565b601f1a60f81b815f81518110612d2057612d20613299565b60200101906001600160f81b03191690815f1a90535061030e565b5f60015b612d4981876131da565b15612d6f5781612d5881613281565b9250612d689050610100826131ed565b9050612d3f565b612d7a826001613204565b67ffffffffffffffff811115612d9257612d926132ad565b6040519080825280601f01601f191660200182016040528015612dbc576020820181803683370190505b509250612dc98583613204565b612dd4906037613204565b601f1a60f81b835f81518110612dec57612dec613299565b60200101906001600160f81b03191690815f1a905350600190505b818111612e7b57610100612e1b828461326e565b612e2790610100613964565b612e3190886131da565b612e3b919061396f565b601f1a60f81b838281518110612e5357612e53613299565b60200101906001600160f81b03191690815f1a90535080612e7381613281565b915050612e07565b50509392505050565b6060806040519050835180825260208201818101602087015b81831015612eb5578051835260209283019201612e9d565b50855184518101855292509050808201602086015b81831015612ee2578051835260209283019201612eca565b508651929092011591909101601f01601f191660405250905092915050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6001600160a01b0381168114612f4a575f5ffd5b50565b5f5f60408385031215612f5e575f5ffd5b8235612f6981612f36565b91506020830135612f7981612f36565b809150509250929050565b5f60208284031215612f94575f5ffd5b813561030e81612f36565b5f5f83601f840112612faf575f5ffd5b50813567ffffffffffffffff811115612fc6575f5ffd5b6020830191508360208285010111156108ee575f5ffd5b5f5f60208385031215612fee575f5ffd5b823567ffffffffffffffff811115613004575f5ffd5b61301085828601612f9f565b90969095509350505050565b5f5f5f5f5f60608688031215613030575f5ffd5b85359450602086013567ffffffffffffffff81111561304d575f5ffd5b61305988828901612f9f565b909550935050604086013567ffffffffffffffff811115613078575f5ffd5b61308488828901612f9f565b969995985093965092949392505050565b5f5f604083850312156130a6575f5ffd5b823567ffffffffffffffff8111156130bc575f5ffd5b830161012081860312156130ce575f5ffd5b946020939093013593505050565b5f602082840312156130ec575f5ffd5b5035919050565b5f5f5f5f60608587031215613106575f5ffd5b843561311181612f36565b935060208501359250604085013567ffffffffffffffff811115613133575f5ffd5b61313f87828801612f9f565b95989497509550505050565b5f5f85851115613159575f5ffd5b83861115613165575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff1981169060148410156124c8576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f826131e8576131e86131b2565b500490565b8082028115828204841417610311576103116131c6565b80820180821115610311576103116131c6565b5f5f8335601e1984360301811261322c575f5ffd5b83018035915067ffffffffffffffff821115613246575f5ffd5b6020019150368190038213156108ee575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b81810381811115610311576103116131c6565b5f60018201613292576132926131c6565b5060010190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b6040516101e0810167ffffffffffffffff811182821017156132e5576132e56132ad565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613314576133146132ad565b604052919050565b5f67ffffffffffffffff821115613335576133356132ad565b5060051b60200190565b5f82601f83011261334e575f5ffd5b815161336161335c8261331c565b6132eb565b8082825260208201915060208360051b860101925085831115613382575f5ffd5b602085015b8381101561339f578051835260209283019201613387565b5095945050505050565b805165ffffffffffff81168114611d03575f5ffd5b5f82601f8301126133cd575f5ffd5b8151602083015f5f67ffffffffffffffff8411156133ed576133ed6132ad565b50601f8301601f1916602001613402816132eb565b915050828152858383011115613416575f5ffd5b8282602083015e5f92810160200192909252509392505050565b5f5f5f5f5f60a08688031215613444575f5ffd5b8551602087015190955067ffffffffffffffff811115613462575f5ffd5b61346e8882890161333f565b94505061347d604087016133a9565b925061348b606087016133a9565b9150608086015167ffffffffffffffff8111156134a6575f5ffd5b6134b2888289016133be565b9150509295509295909350565b8051611d0381612f36565b80518015158114611d03575f5ffd5b5f602082840312156134e9575f5ffd5b815167ffffffffffffffff8111156134ff575f5ffd5b82016101e08185031215613511575f5ffd5b6135196132c1565b613522826134bf565b8152613530602083016134bf565b602082015260408281015190820152606080830151908201526080808301519082015260a0808301519082015260c0808301519082015261357360e083016134ca565b60e0820152610100828101519082015261012082015167ffffffffffffffff81111561359d575f5ffd5b6135a98682850161333f565b610120830152506135bd61014083016133a9565b6101408201526135d061016083016133a9565b61016082015261018082810151908201526101a080830151908201526101c091820151918101919091529392505050565b5f5f5f5f5f5f5f60e0888a031215613617575f5ffd5b87516001600160f81b03198116811461362e575f5ffd5b602089015190975067ffffffffffffffff81111561364a575f5ffd5b6136568a828b016133be565b965050604088015167ffffffffffffffff811115613672575f5ffd5b61367e8a828b016133be565b60608a015190965094506136969050608089016134bf565b60a089015160c08a0151919450925067ffffffffffffffff8111156136b9575f5ffd5b6136c58a828b0161333f565b91505092959891949750929550565b5f5f5f606084860312156136e6575f5ffd5b8351602085015190935067ffffffffffffffff811115613704575f5ffd5b6137108682870161333f565b925050604084015167ffffffffffffffff81111561372c575f5ffd5b613738868287016133be565b9150509250925092565b60ff81811683821602908116908181146124c8576124c86131c6565b805160208201517fffffffffffff00000000000000000000000000000000000000000000000000008116919060068210156137c3577fffffffffffff0000000000000000000000000000000000000000000000000000808360060360031b1b82161692505b5050919050565b5f81518060208401855e5f93019283525090919050565b6001600160f81b03198360f81b1681525f61067360018301846137ca565b5f61063e61381661381084886137ca565b866137ca565b846137ca565b80516020808301519190811015610d78575f1960209190910360031b1b16919050565b60ff8281168282160390811115610311576103116131c6565b5f60ff82168061386a5761386a6131c6565b5f190192915050565b5f61067361381683866137ca565b6001815b60018411156138bc578085048111156138a0576138a06131c6565b60018416156138ae57908102905b60019390931c928002613885565b935093915050565b5f826138d257506001610311565b816138de57505f610311565b81600181146138f457600281146138fe5761391a565b6001915050610311565b60ff84111561390f5761390f6131c6565b50506001821b610311565b5060208310610133831016604e8410600b841016171561393d575081810a610311565b6139495f198484613881565b805f190482111561395c5761395c6131c6565b029392505050565b5f61030e83836138c4565b5f8261397d5761397d6131b2565b50069056fea164736f6c634300081b000a

Deployed Bytecode

0x608060405234801561000f575f5ffd5b50600436106100f0575f3560e01c8063940d384011610093578063e824b56811610063578063e824b56814610283578063ecd0596114610296578063f2fde38b146102aa578063f551e2ee146102bd575f5ffd5b8063940d3840146102165780639700320314610229578063d60b347f1461024a578063d620c85a1461025d575f5ffd5b806354fd4d50116100ce57806354fd4d50146101a25780635c81ca68146101db5780636d61fe70146101f05780638a91b0e314610203575f5ffd5b806306fdde03146100f45780630807dbc11461013f5780632e5b63a614610162575b5f5ffd5b60408051808201909152600e81527f4b314d656556616c696461746f7200000000000000000000000000000000000060208201525b6040516101369190612f01565b60405180910390f35b61015261014d366004612f4d565b610301565b6040519015158152602001610136565b61018a610170366004612f84565b5f602081905290815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610136565b60408051808201909152600581527f312e302e300000000000000000000000000000000000000000000000000000006020820152610129565b6101ee6101e9366004612f84565b610317565b005b6101ee6101fe366004612fdd565b610327565b6101ee610211366004612fdd565b61047a565b61015261022436600461301c565b6104af565b61023c610237366004613095565b61051d565b604051908152602001610136565b610152610258366004612f84565b61055f565b7fd620c85a0000000000000000000000000000000000000000000000000000000061023c565b6101ee610291366004612f84565b610582565b6101526102a43660046130dc565b60011490565b6101ee6102b8366004612f84565b61058e565b6102d06102cb3660046130f3565b610629565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610136565b5f61030e60018385610647565b90505b92915050565b6103236001338361067d565b5050565b5f819003610361576040517f1f2a381c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152602081905260409020546001600160a01b0316156103b0576040517fe72ce85e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6103be601482848661314b565b6103c791613172565b60601c905080610403576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803b15610423576040516383e6a1cb60e01b815260040160405180910390fd5b335f908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316179055601482111561047557610475610470836014818761314b565b610692565b505050565b335f818152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19169055610323906001906106f9565b5f601482146104ea576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6104f8601482858761314b565b61050191613172565b60601c905061051281888888610703565b979650505050505050565b5f80808061052e6020870187612f84565b6001600160a01b03908116825260208201929092526040015f2054169050610557848483610744565b949350505050565b6001600160a01b038082165f908152602081905260408120549091161515610311565b610323600133836108b0565b6001600160a01b0381166105ce576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803b156105ee576040516383e6a1cb60e01b815260040160405180910390fd5b335f908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b5f61063e858561063986866108c5565b6108f5565b95945050505050565b6001600160a01b038181165f908152600185016020908152604080832093861683529290529081205415155b90505b9392505050565b5f61067384846001600160a01b0385166109d7565b5f5b61069f6014836131da565b811015610475576106f03384846106b78560146131ed565b906106c3866001613204565b6106ce9060146131ed565b926106db9392919061314b565b6106e491613172565b6001919060601c61067d565b50600101610694565b6103238282610a5c565b5f61063e858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610ab092505050565b5f80610790610757610100870187613217565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610b6092505050565b90505f815160038111156107a6576107a661325a565b036107c2576107ba85826020015185610d7e565b915050610676565b6001815160038111156107d7576107d761325a565b036107eb576107ba85826020015185610e15565b6002815160038111156108005761080061325a565b03610814576107ba85826020015185610ef0565b6003815160038111156108295761082961325a565b0361083d576107ba84826020015185611147565b60405162461bcd60e51b815260206004820152603260248201527f53757065725478456364736156616c696461746f724c69623a3a20696e76616c60448201527f696420757365724f70207369672074797065000000000000000000000000000060648201526084015b60405180910390fd5b5f61067384846001600160a01b038516611168565b818161649261ffff30801c190402818301601f190135036108ee57506040810135016020810190355b9250929050565b5f816109325761773961ffff83190402840361093257507f7739000100000000000000000000000000000000000000000000000000000000610557565b60208301357f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0811115610991576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61099e87878787611246565b806109af57506109af868686611260565b806109c057506109c08686866114fe565b155f03631626ba7e1760e01b979650505050505050565b5f81815260018401602090815260408083206001600160a01b0386168452909152812054610a55575f838152602085815260409091208054600101918202810184905555610a258484611569565b5f8381526001808701602090815260408084206001600160a01b0389168552909152909120919091559050610676565b505f610676565b5f610a67838361157c565b905060015b818111610aaa575f610a888585610a83858761326e565b611587565b9050610a95858583611168565b50508080610aa290613281565b915050610a6c565b50505050565b5f5f610abb83610b60565b90505f81516003811115610ad157610ad161325a565b03610ae5576107ba85858360200151611593565b600181516003811115610afa57610afa61325a565b03610b0e576107ba858583602001516115f2565b600281516003811115610b2357610b2361325a565b03610b37576107ba8585836020015161169a565b600381516003811115610b4c57610b4c61325a565b0361083d576107ba858583602001516117ec565b604080518082019091525f8152606060208201525f610b8f6001808551610b87919061326e565b8591906117f8565b90505f60ff16835f81518110610ba757610ba7613299565b016020015160f81c03610bd05760408051808201909152805f5b81526020019190915292915050565b600160ff16835f81518110610be757610be7613299565b016020015160f81c03610c065760408051808201909152806001610bc1565b600260ff16835f81518110610c1d57610c1d613299565b016020015160f81c03610c3c5760408051808201909152806002610bc1565b60ff8016835f81518110610c5257610c52613299565b016020015160f81c03610c715760408051808201909152806003610bc1565b60405162461bcd60e51b81526020600482015260b360248201527f53757065725478456364736156616c696461746f724c69623a3a20696e76616c60448201527f69642073696720747970652e204578706563746564207072656669782030783060648201527f3020666f72206f66662d636861696e2c203078303120666f72206f6e2d63686160848201527f696e206f72203078303220666f72206572633230207065726d6974206974782060a48201527f68617368207369676e6174757265206f72203078666620666f72206e6f726d6160c48201527f6c20757365724f70207369676e61747572652e0000000000000000000000000060e4820152610104016108a7565b50919050565b5f5f5f5f5f5f87806020019051810190610d989190613430565b945094509450945094505f610dbe8a8565ffffffffffff168565ffffffffffff1661191f565b9050610dcb888784611986565b610dde5760019650505050505050610676565b610de9858783611a0a565b610dfc5760019650505050505050610676565b610e075f8486611a1f565b9a9950505050505050505050565b5f5f610e2084611a55565b90505f610e47868360e0015165ffffffffffff1684610100015165ffffffffffff1661191f565b90505f826040015183606001518460200151604051602001610e8993929190928352602083019190915260f81b6001600160f81b031916604082015260410190565b6040516020818303038152906040529050610ea985846080015183611986565b610eb95760019350505050610676565b610ecc8360c001518460a0015184611a0a565b610edc5760019350505050610676565b6105125f8461010001518560e00151611a1f565b5f5f83806020019051810190610f0691906134d9565b90505f610f2e8683610140015165ffffffffffff1684610160015165ffffffffffff1661191f565b90505f610f3f836101800151611cae565b6101008401516040808601516020808801516080808a015160c0808c01518751958601969096526001600160a01b03808f169786019790975295909216606084015282015260a0810191909152908101829052919250905f9060e0016040516020818303038152906040528051906020012090505f610fc2828760600151611d08565b6101a08701516101c08801516040805160208101939093528201526001600160f81b031960f887901b1660608201529091505f906061016040516020818303038152906040529050611015898383611986565b611029576001975050505050505050610676565b61103e87610120015188610100015188611a0a565b611052576001975050505050505050610676565b8660e00151156111235786516001600160a01b031663d505accf8a61107a60208f018f612f84565b60808b01516101a08c01516101c08d015160405160e087901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03958616600482015294909316602485015260448401919091526064830189905260ff8a16608484015260a483015260c482015260e4015f604051808303815f87803b15801561110c575f5ffd5b505af115801561111e573d5f5f3e3d5ffd5b505050505b6111385f886101600151896101400151611a1f565b9b9a5050505050505050505050565b5f611153828585611986565b61115f57506001610676565b505f9392505050565b5f81815260018401602090815260408083206001600160a01b0386168452909152812054801561123d575f61119e60018361326e565b90505f60016111ad8888611569565b6111b7919061326e565b9050808214611201575f6111cc888884611d47565b90506111da88888584611d53565b5f90815260018801602090815260408083206001600160a01b038a16845290915290208390555b61120b8787611d5f565b5050505f8281526001808601602090815260408084206001600160a01b03881685529091528220919091559050610676565b5f915050610676565b5f61125085611d69565b156105575761063e848484611da9565b5f308015611319575f5f5f5f5f336001600160a01b03166384b0196e6040518163ffffffff1660e01b81526004015f60405180830381865afa1580156112a8573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112cf9190810190613601565b506040805186516020978801208183015285519590960194909420606086015260808501929092526001600160a01b031660a084015260c083015260e08201905296505050505050505b6040516002840385013560f01c8060420180860387016119015f52604081602037821582881017896042601e20181715611384575f94507f983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de85528860205260408520985050506114dd565b7f5479706564446174615369676e280000000000000000000000000000000000008452600e84018360408301823760288185019081525f1901515f1a6029146113fd575f6001858301035b6001820191506029828203515f1a14868310116113cf57508085039450808560408501018337602881830153505b6f07fffffe00000000000001000000000081515f1a1c5b602882515f1a1461143a57806512010000000183515f1a1c179050600182019150611414565b7f20636f6e74656e74732c737472696e67206e616d652c737472696e670000000082527f2076657273696f6e2c75696e7432353620636861696e49642c61646472657373601c8301527f20766572696679696e67436f6e74726163742c627974657333322073616c7429603c830152605c820191508460408401833760408388379084018590038520865260e08620604052600116604201601e20985050909403935b50604052806114f3576114f03386611dcd565b94505b61063e858585611da9565b5f3a610676573a3a526d378edcd5b5b0a24f5342d8c1048560203a3a388461fffffa503a5161155d57604051631626ba7e3a528160205260408052454561ffff0117805a10838814171561154e57fe5b3a3a6064601c3085fa50506040525b50610673848484611da9565b5f8181526020839052604081205461030e565b5f61030e8383611569565b5f610673848484611d47565b5f5f5f5f848060200190518101906115ab91906136d4565b9250925092506115bc878483611986565b6115cb575f9350505050610676565b6115d6828488611a0a565b6115e5575f9350505050610676565b5060019695505050505050565b5f5f6115fd83611a55565b90505f81604001518260600151836020015160405160200161163f93929190928352602083019190915260f81b6001600160f81b031916604082015260410190565b604051602081830303815290604052905061165f86836080015183611986565b61166d575f92505050610676565b6116808260c001518360a0015187611a0a565b61168e575f92505050610676565b50600195945050505050565b5f5f828060200190518101906116b091906134d9565b90505f6116c1826101800151611cae565b90505f8261010001515f1c90505f836040015188856020015186608001518760c0015186604051602001611729969594939291909586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b6040516020818303038152906040528051906020012090505f611750828660600151611d08565b6101a08601516101c08701516040805160208101939093528201526001600160f81b031960f887901b1660608201529091505f9060610160405160208183030381529060405290506117a38a8383611986565b6117b5575f9650505050505050610676565b6117ca8661012001518761010001518b611a0a565b6117dc575f9650505050505050610676565b5060019998505050505050505050565b5f610673848484611986565b60608161180681601f613204565b10156118545760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f7700000000000000000000000000000000000060448201526064016108a7565b61185e8284613204565b845110156118ae5760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e647300000000000000000000000000000060448201526064016108a7565b6060821580156118cc5760405191505f825260208201604052611916565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119055780518352602092830192016118ed565b5050858452601f01601f1916604052505b50949350505050565b5f61192984611eb8565b60408051602081019290925281018490526060810183905246608082015260a00160408051601f19818403018152828252805160209182012090830152016040516020818303038152906040528051906020012090509392505050565b5f836001600160a01b031661199b8484611ed0565b6001600160a01b0316036119b157506001610676565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c849052603c90206001600160a01b038516906119f49084611ed0565b6001600160a01b03160361115f57506001610676565b5f82611a168584611ee7565b14949350505050565b5f60d08265ffffffffffff16901b60a08465ffffffffffff16901b85611a45575f611a48565b60015b60ff161717949350505050565b60408051610120810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e081018290526101008101919091525f825f81518110611aaf57611aaf613299565b016020015160f81c90505f611ae1611ac960066002613742565b60ff168551611ad8919061326e565b859060066117f8565b611aea9061375e565b60d01c90505f611b0d600660ff168651611b04919061326e565b869060066117f8565b611b169061375e565b60d01c90505f856001611b2b60066002613742565b60ff168851611b3a919061326e565b611b44919061326e565b81518110611b5457611b54613299565b016020015160f81c90505f611b6b60066002613742565b60ff16602060ff168360ff16611b8191906131ed565b611b8c906001613204565b611b969190613204565b90505f611bbe600180848b51611bac919061326e565b611bb6919061326e565b8a91906117f8565b90505f611bf1826040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b90505f611bfd82611f29565b90505f611c0a898361202f565b90506040518061012001604052808a60ff168152602001611c2d835f0151611cae565b60ff1681526020018260200151815260200182604001518152602001611c5e8b87611c57886121aa565b86516121b5565b8152602001611c70836060015161234e565b8152602001611c7f8d896123ee565b81526020018965ffffffffffff1681526020018865ffffffffffff168152509950505050505050505050919050565b5f60258210611cec576023611cc2836124cf565b611ccd9060026131ed565b611cd7908461326e565b611ce1919061326e565b61031190601b613204565b60018211611cff5761031182601b613204565b5090565b919050565b6040517f190100000000000000000000000000000000000000000000000000000000000081526002810182905260228101839052604290205f9061030e565b5f6106738484846124e7565b610aaa848484846124fe565b6103238282612516565b5f6dd9ecebf3c23529de49815dac1c4c6001600160a01b0383161480611d9757506001600160a01b03821633145b80610311575061031160013384610647565b335f90815260208190526040812054610673906001600160a01b0316858585610703565b5f5f5f5f5f866001600160a01b03166384b0196e6040518163ffffffff1660e01b81526004015f60405180830381865afa158015611e0d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e349190810190613601565b50509450945094509450506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815284516020860120602082015283516020850120604082015282606082015281608082015260a081209550506719010000000000005f5284601a5285603a52604260182094505f603a525050505092915050565b5f611ec282612552565b805190602001209050919050565b5f80611edc8484612607565b509095945050505050565b5f81815b8451811015611f2157611f1782868381518110611f0a57611f0a613299565b6020026020010151612650565b9150600101611eeb565b509392505050565b6060611f348261267c565b611f3c575f5ffd5b5f611f46836126b3565b90505f8167ffffffffffffffff811115611f6257611f626132ad565b604051908082528060200260200182016040528015611fa657816020015b604080518082019091525f8082526020820152815260200190600190039081611f805790505b5090505f611fb78560200151612736565b8560200151611fc69190613204565b90505f805b8481101561202457611fdc836127af565b915060405180604001604052808381526020018481525084828151811061200557612005613299565b602090810291909101015261201a8284613204565b9250600101611fcb565b509195945050505050565b61205760405180608001604052805f81526020015f81526020015f8152602001606081525090565b5f80808060ff871661207757506005925060069150600790506008612105565b60011960ff88160161209757506007925060099150600a9050600b612105565b60405162461bcd60e51b815260206004820152602860248201527f547856616c696461746f724c69623a3a20756e737570706f727465642065766d60448201527f207478207479706500000000000000000000000000000000000000000000000060648201526084016108a7565b6040518060800160405280612135888660ff168151811061212857612128613299565b6020026020010151612852565b8152602001612152888560ff168151811061212857612128613299565b5f1b8152602001612171888460ff168151811061212857612128613299565b5f1b815260200161219d888760ff168151811061219057612190613299565b602002602001015161289c565b9052979650505050505050565b5f5f6105578361290e565b5f5f6121c083612950565b516121cc906042613204565b90505f8486516121dc919061326e565b90505f6122038283858a516121f1919061326e565b6121fb919061326e565b8991906117f8565b905060011960ff89160161225b578761222a8260405180602001604052805f815250612963565b60405160200161223b9291906137e1565b604051602081830303815290604052805190602001209350505050610557565b60ff88166122e157602585106122c9576122b88161228061227b886124cf565b612950565b6122895f612950565b6122925f612950565b6040516020016122a4939291906137ff565b604051602081830303815290604052612963565b805190602001209350505050610557565b6122b88160405180602001604052805f815250612963565b60405162461bcd60e51b8152602060048201526024808201527f547856616c696461746f724c69623a3a20756e737570706f727465642074782060448201527f747970650000000000000000000000000000000000000000000000000000000060648201526084016108a7565b5f602060ff16825110156123ca5760405162461bcd60e51b815260206004820152602560248201527f54784465636f6465723a3a2063616c6c44617461206c656e67746820746f6f2060448201527f73686f727400000000000000000000000000000000000000000000000000000060648201526084016108a7565b81516123e5906123dc9060209061326e565b839060206117f8565b6103119061381c565b60608160ff1667ffffffffffffffff81111561240c5761240c6132ad565b604051908082528060200260200182016040528015612435578160200160208202803683370190505b5090505f600161244760066002613742565b60ff168551612456919061326e565b612460919061326e565b90505b60ff8316156124c85761248361247a60208361326e565b859060206117f8565b61248c9061381c565b8261249860018661383f565b60ff16815181106124ab576124ab613299565b6020908102919091010152826124c081613858565b935050612463565b5092915050565b5f60026124dd60238461326e565b61031191906131da565b5f82815260208490526040812061067390836129c3565b5f838152602085905260409020610aaa9083836129e9565b5f818152602083905260408120805490918190036125345750505050565b6125498261254360018461326e565b5f6129e9565b5f190190555050565b6060813560208301355f61257161256c6040870187613217565b612a12565b90505f61258461256c6060880188613217565b9050608086013560a087013560c08801355f6125a661256c60e08c018c613217565b604080516001600160a01b039a909a1660208b015289810198909852606089019690965250608087019390935260a086019190915260c085015260e08401526101008084019190915281518084039091018152610120909201905292915050565b5f5f5f835160410361263e576020840151604085015160608601515f1a61263088828585612a24565b955095509550505050612649565b505081515f91506002905b9250925092565b5f81831061266a575f82815260208490526040902061030e565b5f83815260208390526040902061030e565b80515f90810361268d57505f919050565b602082015180515f1a9060c08210156126a957505f9392505050565b5060019392505050565b80515f9081036126c457505f919050565b5f5f90505f6126d68460200151612736565b84602001516126e59190613204565b90505f845f015185602001516126fb9190613204565b90505b8082101561272d5761270f826127af565b6127199083613204565b91508261272581613281565b9350506126fe565b50909392505050565b80515f90811a608081101561274d57505f92915050565b60b8811080612768575060c08110801590612768575060f881105b156127765750600192915050565b60c08110156127a35761278b600160b861383f565b6127989060ff168261326e565b610676906001613204565b61278b600160f861383f565b80515f908190811a60808110156127c957600191506124c8565b60b88110156127ef576127dd60808261326e565b6127e8906001613204565b91506124c8565b60c081101561281c5760b78103600185019450806020036101000a855104600182018101935050506124c8565b60f8811015612830576127dd60c08261326e565b60019390930151602084900360f7016101000a900490920160f5190192915050565b80515f901580159061286657508151602110155b61286e575f5ffd5b5f5f6128798461290e565b8151919350915060208210156105575760208290036101000a9004949350505050565b80516060906128a9575f5ffd5b5f5f6128b48461290e565b915091505f8167ffffffffffffffff8111156128d2576128d26132ad565b6040519080825280601f01601f1916602001820160405280156128fc576020820181803683370190505b50905060208101611916848285612aec565b5f5f5f61291e8460200151612736565b90505f8185602001516129319190613204565b90505f82865f0151612943919061326e565b9196919550909350505050565b606061031161295e83612b6c565b612c84565b60605f8383604051602001612979929190613873565b60408051601f1981840301815291905280519091506129999060c0612cd3565b816040516020016129ab929190613873565b60405160208183030381529060405291505092915050565b5f825482106129dd57638277484f5f52816020526024601cfd5b50600101602002015490565b82548210612a0257638277484f5f52816020526024601cfd5b8060018301602002840155505050565b5f604051828085833790209392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612a5d57505f91506003905082612ae2565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015612aae573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116612ad957505f925060019150829050612ae2565b92505f91508190505b9450945094915050565b805f03612af857505050565b60208110612b305782518252612b0f602084613204565b9250612b1c602083613204565b9150612b2960208261326e565b9050612af8565b8015610475575f6001612b4483602061326e565b612b5090610100613964565b612b5a919061326e565b84518451821691191617835250505050565b6040805160208082528183019092526060915f91906020820181803683375050506020810184905290505f5b6020811015612bd057818181518110612bb357612bb3613299565b01602001516001600160f81b0319165f03612bd057600101612b98565b5f612bdc82602061326e565b67ffffffffffffffff811115612bf457612bf46132ad565b6040519080825280601f01601f191660200182016040528015612c1e576020820181803683370190505b5090505f5b8151811015611916578383612c3781613281565b945081518110612c4957612c49613299565b602001015160f81c60f81b828281518110612c6657612c66613299565b60200101906001600160f81b03191690815f1a905350600101612c23565b60608082516001148015612cb157506080835f81518110612ca757612ca7613299565b016020015160f81c105b15612cbd575081610311565b61030e83612ccd85516080612cd3565b90612e84565b6060806038841015612d3b5760408051600180825281830190925290602082018180368337019050509050612d088385613204565b601f1a60f81b815f81518110612d2057612d20613299565b60200101906001600160f81b03191690815f1a90535061030e565b5f60015b612d4981876131da565b15612d6f5781612d5881613281565b9250612d689050610100826131ed565b9050612d3f565b612d7a826001613204565b67ffffffffffffffff811115612d9257612d926132ad565b6040519080825280601f01601f191660200182016040528015612dbc576020820181803683370190505b509250612dc98583613204565b612dd4906037613204565b601f1a60f81b835f81518110612dec57612dec613299565b60200101906001600160f81b03191690815f1a905350600190505b818111612e7b57610100612e1b828461326e565b612e2790610100613964565b612e3190886131da565b612e3b919061396f565b601f1a60f81b838281518110612e5357612e53613299565b60200101906001600160f81b03191690815f1a90535080612e7381613281565b915050612e07565b50509392505050565b6060806040519050835180825260208201818101602087015b81831015612eb5578051835260209283019201612e9d565b50855184518101855292509050808201602086015b81831015612ee2578051835260209283019201612eca565b508651929092011591909101601f01601f191660405250905092915050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6001600160a01b0381168114612f4a575f5ffd5b50565b5f5f60408385031215612f5e575f5ffd5b8235612f6981612f36565b91506020830135612f7981612f36565b809150509250929050565b5f60208284031215612f94575f5ffd5b813561030e81612f36565b5f5f83601f840112612faf575f5ffd5b50813567ffffffffffffffff811115612fc6575f5ffd5b6020830191508360208285010111156108ee575f5ffd5b5f5f60208385031215612fee575f5ffd5b823567ffffffffffffffff811115613004575f5ffd5b61301085828601612f9f565b90969095509350505050565b5f5f5f5f5f60608688031215613030575f5ffd5b85359450602086013567ffffffffffffffff81111561304d575f5ffd5b61305988828901612f9f565b909550935050604086013567ffffffffffffffff811115613078575f5ffd5b61308488828901612f9f565b969995985093965092949392505050565b5f5f604083850312156130a6575f5ffd5b823567ffffffffffffffff8111156130bc575f5ffd5b830161012081860312156130ce575f5ffd5b946020939093013593505050565b5f602082840312156130ec575f5ffd5b5035919050565b5f5f5f5f60608587031215613106575f5ffd5b843561311181612f36565b935060208501359250604085013567ffffffffffffffff811115613133575f5ffd5b61313f87828801612f9f565b95989497509550505050565b5f5f85851115613159575f5ffd5b83861115613165575f5ffd5b5050820193919092039150565b80356bffffffffffffffffffffffff1981169060148410156124c8576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f826131e8576131e86131b2565b500490565b8082028115828204841417610311576103116131c6565b80820180821115610311576103116131c6565b5f5f8335601e1984360301811261322c575f5ffd5b83018035915067ffffffffffffffff821115613246575f5ffd5b6020019150368190038213156108ee575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b81810381811115610311576103116131c6565b5f60018201613292576132926131c6565b5060010190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b6040516101e0810167ffffffffffffffff811182821017156132e5576132e56132ad565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613314576133146132ad565b604052919050565b5f67ffffffffffffffff821115613335576133356132ad565b5060051b60200190565b5f82601f83011261334e575f5ffd5b815161336161335c8261331c565b6132eb565b8082825260208201915060208360051b860101925085831115613382575f5ffd5b602085015b8381101561339f578051835260209283019201613387565b5095945050505050565b805165ffffffffffff81168114611d03575f5ffd5b5f82601f8301126133cd575f5ffd5b8151602083015f5f67ffffffffffffffff8411156133ed576133ed6132ad565b50601f8301601f1916602001613402816132eb565b915050828152858383011115613416575f5ffd5b8282602083015e5f92810160200192909252509392505050565b5f5f5f5f5f60a08688031215613444575f5ffd5b8551602087015190955067ffffffffffffffff811115613462575f5ffd5b61346e8882890161333f565b94505061347d604087016133a9565b925061348b606087016133a9565b9150608086015167ffffffffffffffff8111156134a6575f5ffd5b6134b2888289016133be565b9150509295509295909350565b8051611d0381612f36565b80518015158114611d03575f5ffd5b5f602082840312156134e9575f5ffd5b815167ffffffffffffffff8111156134ff575f5ffd5b82016101e08185031215613511575f5ffd5b6135196132c1565b613522826134bf565b8152613530602083016134bf565b602082015260408281015190820152606080830151908201526080808301519082015260a0808301519082015260c0808301519082015261357360e083016134ca565b60e0820152610100828101519082015261012082015167ffffffffffffffff81111561359d575f5ffd5b6135a98682850161333f565b610120830152506135bd61014083016133a9565b6101408201526135d061016083016133a9565b61016082015261018082810151908201526101a080830151908201526101c091820151918101919091529392505050565b5f5f5f5f5f5f5f60e0888a031215613617575f5ffd5b87516001600160f81b03198116811461362e575f5ffd5b602089015190975067ffffffffffffffff81111561364a575f5ffd5b6136568a828b016133be565b965050604088015167ffffffffffffffff811115613672575f5ffd5b61367e8a828b016133be565b60608a015190965094506136969050608089016134bf565b60a089015160c08a0151919450925067ffffffffffffffff8111156136b9575f5ffd5b6136c58a828b0161333f565b91505092959891949750929550565b5f5f5f606084860312156136e6575f5ffd5b8351602085015190935067ffffffffffffffff811115613704575f5ffd5b6137108682870161333f565b925050604084015167ffffffffffffffff81111561372c575f5ffd5b613738868287016133be565b9150509250925092565b60ff81811683821602908116908181146124c8576124c86131c6565b805160208201517fffffffffffff00000000000000000000000000000000000000000000000000008116919060068210156137c3577fffffffffffff0000000000000000000000000000000000000000000000000000808360060360031b1b82161692505b5050919050565b5f81518060208401855e5f93019283525090919050565b6001600160f81b03198360f81b1681525f61067360018301846137ca565b5f61063e61381661381084886137ca565b866137ca565b846137ca565b80516020808301519190811015610d78575f1960209190910360031b1b16919050565b60ff8281168282160390811115610311576103116131c6565b5f60ff82168061386a5761386a6131c6565b5f190192915050565b5f61067361381683866137ca565b6001815b60018411156138bc578085048111156138a0576138a06131c6565b60018416156138ae57908102905b60019390931c928002613885565b935093915050565b5f826138d257506001610311565b816138de57505f610311565b81600181146138f457600281146138fe5761391a565b6001915050610311565b60ff84111561390f5761390f6131c6565b50506001821b610311565b5060208310610133831016604e8410600b841016171561393d575081810a610311565b6139495f198484613881565b805f190482111561395c5761395c6131c6565b029392505050565b5f61030e83836138c4565b5f8261397d5761397d6131b2565b50069056fea164736f6c634300081b000a

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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