ETH Price: $2,663.47 (-3.49%)

Contract

0x000000009B1D0aF20D8C6d0A44e162d11F9b8f00

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

1 address found via
Transaction Hash
Block
From
To
Revoke304190862025-10-22 21:10:4599 days ago1761167445IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.0001003
Revoke304190692025-10-22 21:10:2899 days ago1761167428IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.0001003
Transfer276945702025-09-21 8:22:09131 days ago1758442929IN
Uniswap: EIP-7702 Delegator 1
0 ETH0.000000040.00100029
Transfer271794272025-09-15 9:16:26137 days ago1757927786IN
Uniswap: EIP-7702 Delegator 1
0 ETH0.000000040.00100037
Transfer From Na...253938722025-08-25 17:17:11158 days ago1756142231IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.00010032
Transfer From Na...253938582025-08-25 17:16:57158 days ago1756142217IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.00010032
Transfer From Na...253938282025-08-25 17:16:27158 days ago1756142187IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.00010032
Transfer From Na...253938202025-08-25 17:16:19158 days ago1756142179IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.00010032
Transfer From Na...253937712025-08-25 17:15:30158 days ago1756142130IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.00010031
Transfer From Na...253936662025-08-25 17:13:45158 days ago1756142025IN
Uniswap: EIP-7702 Delegator 1
0 ETH00.0001003

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
172805592025-05-23 19:35:18251 days ago1748028918  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CaliburEntry

Compiler Version
v0.8.29+commit.ab55807c

Optimization Enabled:
Yes with 10000 runs

Other Settings:
cancun EvmVersion, MIT license
File 1 of 63 : CaliburEntry.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;

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

//    .-.......                                             .::::--=:
//     ==-......                                          ..::---+*=.
//     -===:......                                       ..::--=+**=
//     :====-:......                                   ..:::-=+++*+-
//      :=+===-:......                               ...:::=+++++=:
//        :=+++=-......                            ....::-+++++=:
//          -++++=-......                        .....:-=++++=:
//           .-++++=-......                     ....:-==+===:
//             .=+*++=:......                 .....:-=====-.
//               .=**++=:......             .....:-=====-.
//                 .=**++-:.....          ......-==++=-.
//                   :+**++-:.....       .....:=++++=.
//                     :+**+=-......   .....:=++++=.
//                       -+*++=:...........-++++=:
//                         -+++=-:.......-=++++:
//                           -++-......-=++*+:
//                            .:.....:=++*+-
//                 .          .....:=++**+==:           .
//             -*#*#*:      .....:=++***+----:.      -*###+.
//             .+####=    .....:=++******+=::::..   .+##%#-
//              -####*- .....:-++*+-. :+**++-:....  =##%%+.
//               =####*-....-++*+=.     :+**+=-:...=###%#:
//               .+%###*:.-+***=.         :+**+=-:+##%%*.
//                :*%%###*+**=.             :+***###%%%+.
//               =*##%%#####*-.            .-+#%##%%%%###-
//             :*#*#%%%%%######*+=:    :+######%%%%%%%%###+:
//           .+#*##%%%%#+*%%%#####+.   -###%%%%#=:=#%%%%%###=.
//          -*###%%%%#=.   :=*#%%%+.   -###*=:.    .=#%%%%%##+:
//        :+###%%%%#=.         .:-.                  .=#%%%%##*=.
//     :=++*#%%@@#-.                                   .-#%%%#*====.
//    -=-:-=*#%*-                                         :*#+-::-==.
//    =====++*-                                            :+*+==+++:
//    -*****#=                                              :+####*-
//     .-==-.                                                 .:::

/// @notice Uses custom storage layout according to ERC7201
/// @custom:storage-location erc7201:Uniswap.Calibur.1.0.0
/// @dev keccak256(abi.encode(uint256(keccak256("Uniswap.Calibur.1.0.0")) - 1)) & ~bytes32(uint256(0xff))
contract CaliburEntry is Calibur layout at 0x3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600 {}

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

import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
import {Receiver} from "solady/accounts/Receiver.sol";
import {P256} from "@openzeppelin/contracts/utils/cryptography/P256.sol";
import {IAccount} from "account-abstraction/interfaces/IAccount.sol";
import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
import {IERC1271} from "./interfaces/IERC1271.sol";
import {IERC7821} from "./interfaces/IERC7821.sol";
import {IHook} from "./interfaces/IHook.sol";
import {IKeyManagement} from "./interfaces/IKeyManagement.sol";
import {ICalibur} from "./interfaces/ICalibur.sol";
import {EIP712} from "./EIP712.sol";
import {ERC1271} from "./ERC1271.sol";
import {ERC4337Account} from "./ERC4337Account.sol";
import {ERC7201} from "./ERC7201.sol";
import {ERC7821} from "./ERC7821.sol";
import {ERC7914} from "./ERC7914.sol";
import {ERC7739} from "./ERC7739.sol";
import {KeyManagement} from "./KeyManagement.sol";
import {Multicall} from "./Multicall.sol";
import {NonceManager} from "./NonceManager.sol";
import {BatchedCallLib, BatchedCall} from "./libraries/BatchedCallLib.sol";
import {Call, CallLib} from "./libraries/CallLib.sol";
import {CalldataDecoder} from "./libraries/CalldataDecoder.sol";
import {ERC7739Utils} from "./libraries/ERC7739Utils.sol";
import {HooksLib} from "./libraries/HooksLib.sol";
import {Key, KeyLib} from "./libraries/KeyLib.sol";
import {ModeDecoder} from "./libraries/ModeDecoder.sol";
import {Settings, SettingsLib} from "./libraries/SettingsLib.sol";
import {SignedBatchedCallLib, SignedBatchedCall} from "./libraries/SignedBatchedCallLib.sol";
import {WrappedSignatureLib} from "./libraries/WrappedSignatureLib.sol";

/// @title Calibur
/// @notice A singleton contract wallet supporting batched transactions, alternative signers, and native ETH transferFrom
/// @dev Delegate to Calibur from an EOA using EIP-7702
/// @custom:security-contact [email protected]
contract Calibur is
    ICalibur,
    ERC7821,
    ERC1271,
    ERC4337Account,
    KeyManagement,
    NonceManager,
    ERC7914,
    ERC7201,
    ERC7739,
    EIP712,
    Multicall,
    Receiver
{
    using EnumerableSetLib for EnumerableSetLib.Bytes32Set;
    using CallLib for Call[];
    using BatchedCallLib for BatchedCall;
    using SignedBatchedCallLib for SignedBatchedCall;
    using KeyLib for *;
    using ModeDecoder for bytes32;
    using CalldataDecoder for bytes;
    using HooksLib for IHook;
    using SettingsLib for Settings;
    using ERC7739Utils for bytes;
    using WrappedSignatureLib for bytes;

    /// @inheritdoc ICalibur
    function execute(BatchedCall memory batchedCall) public payable {
        bytes32 keyHash = msg.sender.toKeyHash();
        if (!_isOwnerOrValidKey(keyHash)) revert Unauthorized();
        _processBatch(batchedCall, keyHash);
    }

    /// @inheritdoc ICalibur
    function execute(SignedBatchedCall calldata signedBatchedCall, bytes calldata wrappedSignature) public payable {
        if (!_senderIsExecutor(signedBatchedCall.executor)) revert Unauthorized();
        _handleVerifySignature(signedBatchedCall, wrappedSignature);
        _processBatch(signedBatchedCall.batchedCall, signedBatchedCall.keyHash);
    }

    /// @inheritdoc IERC7821
    function execute(bytes32 mode, bytes calldata executionData) external payable override {
        if (!mode.isBatchedCall()) revert IERC7821.UnsupportedExecutionMode();
        Call[] memory calls = abi.decode(executionData, (Call[]));
        BatchedCall memory batchedCall = BatchedCall({calls: calls, revertOnFailure: mode.revertOnFailure()});
        execute(batchedCall);
    }

    /// @dev This function is executeable only by the EntryPoint contract, and is the main pathway for UserOperations to be executed.
    /// UserOperations can be executed through the execute function, but another method of authorization (ie through a passed in signature) is required.
    /// userOp.callData is abi.encodeCall(IAccountExecute.executeUserOp.selector, (abi.encode(Call[]), bool))
    /// Note that this contract is only compatible with Entrypoint versions v0.7.0 and v0.8.0. It is not compatible with v0.6.0, as that version does not support the "executeUserOp" selector.
    function executeUserOp(PackedUserOperation calldata userOp, bytes32) external onlyEntryPoint {
        // Parse the keyHash from the signature. This is the keyHash that has been pre-validated as the correct signer over the UserOp data
        // and must be used to check further on-chain permissions over the call execution.
        (bytes32 keyHash,,) = userOp.signature.decodeWithKeyHashAndHookData();

        // The mode is only passed in to signify the EXEC_TYPE of the calls.
        bytes calldata executionData = userOp.callData.removeSelector();
        (BatchedCall memory batchedCall) = abi.decode(executionData, (BatchedCall));

        _processBatch(batchedCall, keyHash);
    }

    /// @inheritdoc IAccount
    /// @dev Only return validationData if the signature from the key associated with `keyHash` is valid over the userOpHash
    ///      - The ERC-4337 spec requires that `validateUserOp` does not early return if the signature is invalid such that accurate gas estimation can be done
    /// @return validationData is (uint256(validAfter) << (160 + 48)) | (uint256(validUntil) << 160) | (isValid ? 0 : 1)
    /// - `validAfter` is always 0.
    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
        external
        onlyEntryPoint
        returns (uint256 validationData)
    {
        _payEntryPoint(missingAccountFunds);
        (bytes32 keyHash, bytes calldata signature, bytes calldata hookData) =
            userOp.signature.decodeWithKeyHashAndHookData();

        /// The userOpHash does not need to be made replay-safe, as the EntryPoint will always call the sender contract of the UserOperation for validation.
        Key memory key = getKey(keyHash);
        bool isValid = key.verify(userOpHash, signature);

        Settings settings = getKeySettings(keyHash);

        /// validationData is (uint256(validAfter) << (160 + 48)) | (uint256(validUntil) << 160) | (success ? 0 : 1)
        /// `validAfter` is always 0.
        validationData =
            isValid ? uint256(settings.expiration()) << 160 | SIG_VALIDATION_SUCCEEDED : SIG_VALIDATION_FAILED;

        settings.hook().handleAfterValidateUserOp(keyHash, userOp, userOpHash, validationData, hookData);
    }

    /// @inheritdoc ERC1271
    function isValidSignature(bytes32 digest, bytes calldata wrappedSignature)
        public
        view
        override(ERC1271, IERC1271)
        returns (bytes4)
    {
        // Per ERC-7739, return 0x77390001 for the sentinel hash value
        unchecked {
            if (wrappedSignature.isEmpty()) {
                // Forces the compiler to optimize for smaller bytecode size.
                if (uint256(digest) == ~wrappedSignature.length / 0xffff * 0x7739) return 0x77390001;
            }
            // If the signature is 64 or 65 bytes, it must be validated as an ECDSA signature from the root key
            // We skip any checks against expiry or hooks because settings are not supported on the root key
            else if (wrappedSignature.isRawSignature()) {
                if (KeyLib.toRootKey().verify(digest, wrappedSignature)) {
                    return _1271_MAGIC_VALUE;
                } else {
                    return _1271_INVALID_VALUE;
                }
            }
        }

        (bytes32 keyHash, bytes calldata signature, bytes calldata hookData) =
            wrappedSignature.decodeWithKeyHashAndHookData();

        Key memory key = getKey(keyHash);
        /// Signature deduction flow as specified by ERC-7739
        // If the signature contains enough data for a TypedDataSign, try the TypedDataSign flow
        bool isValid = _isValidTypedDataSig(key, digest, domainBytes(), signature)
        // If the signature is not valid as a TypedDataSign, try the NestedPersonalSign flow
        || _isValidNestedPersonalSig(key, digest, domainSeparator(), signature);

        // Early return if the signature is invalid
        if (!isValid) return _1271_INVALID_VALUE;

        Settings settings = getKeySettings(keyHash);
        _checkExpiry(settings);

        settings.hook().handleAfterIsValidSignature(keyHash, digest, hookData);

        return _1271_MAGIC_VALUE;
    }

    /// @dev Iterates through calls, reverting according to specified failure mode
    function _processBatch(BatchedCall memory batchedCall, bytes32 keyHash) private {
        for (uint256 i = 0; i < batchedCall.calls.length; i++) {
            (bool success, bytes memory output) = _process(batchedCall.calls[i], keyHash);
            // Reverts with the first call that is unsuccessful if `revertOnFailure` is set to true
            // This does not catch hook reverts which cause the entire call to revert regardless of the value of `revertOnFailure`
            if (!success && batchedCall.revertOnFailure) revert ICalibur.CallFailed(output);
        }
    }

    /// @dev Executes a low level call using execution hooks if set
    function _process(Call memory _call, bytes32 keyHash) private returns (bool success, bytes memory output) {
        // Per ERC7821, replace address(0) with address(this)
        address to = _call.to == address(0) ? address(this) : _call.to;

        Settings settings = getKeySettings(keyHash);

        // By default, only the root key or admin keys can self-call. This is to prevent untrusted keys from updating their own settings
        // However, admin keys CAN update their own settings and evade the hook checks below
        // To prevent this, we recommend adding a hook which disallows calls by admin keys to the `register` and `update` functions
        if (!settings.isAdmin() && to == address(this)) revert IKeyManagement.OnlyAdminCanSelfCall();

        IHook hook = settings.hook();
        bytes memory beforeExecuteData = hook.handleBeforeExecute(keyHash, to, _call.value, _call.data);

        (success, output) = to.call{value: _call.value}(_call.data);

        hook.handleAfterExecute(keyHash, success, output, beforeExecuteData);
    }

    /// @dev This function is used to handle the verification of signatures sent through execute()
    function _handleVerifySignature(SignedBatchedCall calldata signedBatchedCall, bytes calldata wrappedSignature)
        private
    {
        uint256 deadline = signedBatchedCall.deadline;
        if (deadline != 0 && block.timestamp > deadline) revert SignatureExpired();

        _useNonce(signedBatchedCall.nonce);

        (bytes calldata signature, bytes calldata hookData) = wrappedSignature.decodeWithHookData();

        bytes32 digest = hashTypedData(signedBatchedCall.hash());

        Key memory key = getKey(signedBatchedCall.keyHash);
        bool isValid = key.verify(digest, signature);
        if (!isValid) revert ICalibur.InvalidSignature();

        Settings settings = getKeySettings(signedBatchedCall.keyHash);
        _checkExpiry(settings);

        settings.hook().handleAfterVerifySignature(signedBatchedCall.keyHash, digest, hookData);
    }

    /// @notice Returns true if the msg.sender is the executor or if the executor is address(0)
    /// @param executor The address of the allowed executor of the signed batched call
    function _senderIsExecutor(address executor) private view returns (bool) {
        return executor == address(0) || executor == msg.sender;
    }
}

File 3 of 63 : EnumerableSetLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for managing enumerable sets in storage.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EnumerableSetLib.sol)
///
/// @dev Note:
/// In many applications, the number of elements in an enumerable set is small.
/// This enumerable set implementation avoids storing the length and indices
/// for up to 3 elements. Once the length exceeds 3 for the first time, the length
/// and indices will be initialized. The amortized cost of adding elements is O(1).
///
/// The AddressSet implementation packs the length with the 0th entry.
///
/// All enumerable sets except Uint8Set use a pop and swap mechanism to remove elements.
/// This means that the iteration order of elements can change between element removals.
library EnumerableSetLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The index must be less than the length.
    error IndexOutOfBounds();

    /// @dev The value cannot be the zero sentinel.
    error ValueIsZeroSentinel();

    /// @dev Cannot accommodate a new unique value with the capacity.
    error ExceedsCapacity();

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

    /// @dev A sentinel value to denote the zero value in storage.
    /// No elements can be equal to this value.
    /// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`.
    uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf;

    /// @dev The storage layout is given by:
    /// ```
    ///     mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
    ///     mstore(0x00, set.slot)
    ///     let rootSlot := keccak256(0x00, 0x24)
    ///     mstore(0x20, rootSlot)
    ///     mstore(0x00, shr(96, shl(96, value)))
    ///     let positionSlot := keccak256(0x00, 0x40)
    ///     let valueSlot := add(rootSlot, sload(positionSlot))
    ///     let valueInStorage := shr(96, sload(valueSlot))
    ///     let lazyLength := shr(160, shl(160, sload(rootSlot)))
    /// ```
    uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92;

    /// @dev The storage layout is given by:
    /// ```
    ///     mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
    ///     mstore(0x00, set.slot)
    ///     let rootSlot := keccak256(0x00, 0x24)
    ///     mstore(0x20, rootSlot)
    ///     mstore(0x00, value)
    ///     let positionSlot := keccak256(0x00, 0x40)
    ///     let valueSlot := add(rootSlot, sload(positionSlot))
    ///     let valueInStorage := sload(valueSlot)
    ///     let lazyLength := sload(not(rootSlot))
    /// ```
    uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864;

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

    /// @dev An enumerable address set in storage.
    struct AddressSet {
        uint256 _spacer;
    }

    /// @dev An enumerable bytes32 set in storage.
    struct Bytes32Set {
        uint256 _spacer;
    }

    /// @dev An enumerable uint256 set in storage.
    struct Uint256Set {
        uint256 _spacer;
    }

    /// @dev An enumerable int256 set in storage.
    struct Int256Set {
        uint256 _spacer;
    }

    /// @dev An enumerable uint8 set in storage. Useful for enums.
    struct Uint8Set {
        uint256 data;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     GETTERS / SETTERS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of elements in the set.
    function length(AddressSet storage set) internal view returns (uint256 result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let rootPacked := sload(rootSlot)
            let n := shr(160, shl(160, rootPacked))
            result := shr(1, n)
            for {} iszero(or(iszero(shr(96, rootPacked)), n)) {} {
                result := 1
                if iszero(sload(add(rootSlot, result))) { break }
                result := 2
                if iszero(sload(add(rootSlot, result))) { break }
                result := 3
                break
            }
        }
    }

    /// @dev Returns the number of elements in the set.
    function length(Bytes32Set storage set) internal view returns (uint256 result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let n := sload(not(rootSlot))
            result := shr(1, n)
            for {} iszero(n) {} {
                result := 0
                if iszero(sload(add(rootSlot, result))) { break }
                result := 1
                if iszero(sload(add(rootSlot, result))) { break }
                result := 2
                if iszero(sload(add(rootSlot, result))) { break }
                result := 3
                break
            }
        }
    }

    /// @dev Returns the number of elements in the set.
    function length(Uint256Set storage set) internal view returns (uint256 result) {
        result = length(_toBytes32Set(set));
    }

    /// @dev Returns the number of elements in the set.
    function length(Int256Set storage set) internal view returns (uint256 result) {
        result = length(_toBytes32Set(set));
    }

    /// @dev Returns the number of elements in the set.
    function length(Uint8Set storage set) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let packed := sload(set.slot) } packed { result := add(1, result) } {
                packed := xor(packed, and(packed, add(1, not(packed))))
            }
        }
    }

    /// @dev Returns whether `value` is in the set.
    function contains(AddressSet storage set, address value) internal view returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for {} 1 {} {
                if iszero(shr(160, shl(160, rootPacked))) {
                    result := 1
                    if eq(shr(96, rootPacked), value) { break }
                    if eq(shr(96, sload(add(rootSlot, 1))), value) { break }
                    if eq(shr(96, sload(add(rootSlot, 2))), value) { break }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                result := iszero(iszero(sload(keccak256(0x00, 0x40))))
                break
            }
        }
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for {} 1 {} {
                if iszero(sload(not(rootSlot))) {
                    result := 1
                    if eq(sload(rootSlot), value) { break }
                    if eq(sload(add(rootSlot, 1)), value) { break }
                    if eq(sload(add(rootSlot, 2)), value) { break }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                result := iszero(iszero(sload(keccak256(0x00, 0x40))))
                break
            }
        }
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) {
        result = contains(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Int256Set storage set, int256 value) internal view returns (bool result) {
        result = contains(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Uint8Set storage set, uint8 value) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(1, shr(and(0xff, value), sload(set.slot)))
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(AddressSet storage set, address value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
                mstore(0x20, rootSlot)
                if iszero(n) {
                    let v0 := shr(96, rootPacked)
                    if iszero(v0) {
                        sstore(rootSlot, shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v0, value) { break }
                    let v1 := shr(96, sload(add(rootSlot, 1)))
                    if iszero(v1) {
                        sstore(add(rootSlot, 1), shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v1, value) { break }
                    let v2 := shr(96, sload(add(rootSlot, 2)))
                    if iszero(v2) {
                        sstore(add(rootSlot, 2), shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v2, value) { break }
                    mstore(0x00, v0)
                    sstore(keccak256(0x00, 0x40), 1)
                    mstore(0x00, v1)
                    sstore(keccak256(0x00, 0x40), 2)
                    mstore(0x00, v2)
                    sstore(keccak256(0x00, 0x40), 3)
                    rootPacked := or(rootPacked, 7)
                    n := 7
                }
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                if iszero(sload(p)) {
                    n := shr(1, n)
                    result := 1
                    sstore(p, add(1, n))
                    if iszero(n) {
                        sstore(rootSlot, or(3, shl(96, value)))
                        break
                    }
                    sstore(add(rootSlot, n), shl(96, value))
                    sstore(rootSlot, add(2, rootPacked))
                    break
                }
                break
            }
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for { let n := sload(not(rootSlot)) } 1 {} {
                mstore(0x20, rootSlot)
                if iszero(n) {
                    let v0 := sload(rootSlot)
                    if iszero(v0) {
                        sstore(rootSlot, value)
                        result := 1
                        break
                    }
                    if eq(v0, value) { break }
                    let v1 := sload(add(rootSlot, 1))
                    if iszero(v1) {
                        sstore(add(rootSlot, 1), value)
                        result := 1
                        break
                    }
                    if eq(v1, value) { break }
                    let v2 := sload(add(rootSlot, 2))
                    if iszero(v2) {
                        sstore(add(rootSlot, 2), value)
                        result := 1
                        break
                    }
                    if eq(v2, value) { break }
                    mstore(0x00, v0)
                    sstore(keccak256(0x00, 0x40), 1)
                    mstore(0x00, v1)
                    sstore(keccak256(0x00, 0x40), 2)
                    mstore(0x00, v2)
                    sstore(keccak256(0x00, 0x40), 3)
                    n := 7
                }
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                if iszero(sload(p)) {
                    n := shr(1, n)
                    sstore(add(rootSlot, n), value)
                    sstore(p, add(1, n))
                    sstore(not(rootSlot), or(1, shl(1, add(1, n))))
                    result := 1
                    break
                }
                break
            }
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Uint256Set storage set, uint256 value) internal returns (bool result) {
        result = add(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Int256Set storage set, int256 value) internal returns (bool result) {
        result = add(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Uint8Set storage set, uint8 value) internal returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(set.slot)
            let mask := shl(and(0xff, value), 1)
            sstore(set.slot, or(result, mask))
            result := iszero(and(result, mask))
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
    function add(AddressSet storage set, address value, uint256 cap)
        internal
        returns (bool result)
    {
        if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
    function add(Bytes32Set storage set, bytes32 value, uint256 cap)
        internal
        returns (bool result)
    {
        if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
    function add(Uint256Set storage set, uint256 value, uint256 cap)
        internal
        returns (bool result)
    {
        if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
    function add(Int256Set storage set, int256 value, uint256 cap) internal returns (bool result) {
        if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
    function add(Uint8Set storage set, uint8 value, uint256 cap) internal returns (bool result) {
        if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(AddressSet storage set, address value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
                if iszero(n) {
                    result := 1
                    if eq(shr(96, rootPacked), value) {
                        sstore(rootSlot, sload(add(rootSlot, 1)))
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(shr(96, sload(add(rootSlot, 1))), value) {
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(shr(96, sload(add(rootSlot, 2))), value) {
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                let position := sload(p)
                if iszero(position) { break }
                n := sub(shr(1, n), 1)
                if iszero(eq(sub(position, 1), n)) {
                    let lastValue := shr(96, sload(add(rootSlot, n)))
                    sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue))
                    mstore(0x00, lastValue)
                    sstore(keccak256(0x00, 0x40), position)
                }
                sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1)))
                sstore(p, 0)
                result := 1
                break
            }
        }
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for { let n := sload(not(rootSlot)) } 1 {} {
                if iszero(n) {
                    result := 1
                    if eq(sload(rootSlot), value) {
                        sstore(rootSlot, sload(add(rootSlot, 1)))
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(sload(add(rootSlot, 1)), value) {
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(sload(add(rootSlot, 2)), value) {
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                let position := sload(p)
                if iszero(position) { break }
                n := sub(shr(1, n), 1)
                if iszero(eq(sub(position, 1), n)) {
                    let lastValue := sload(add(rootSlot, n))
                    sstore(add(rootSlot, sub(position, 1)), lastValue)
                    mstore(0x00, lastValue)
                    sstore(keccak256(0x00, 0x40), position)
                }
                sstore(not(rootSlot), or(shl(1, n), 1))
                sstore(p, 0)
                result := 1
                break
            }
        }
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Uint256Set storage set, uint256 value) internal returns (bool result) {
        result = remove(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Int256Set storage set, int256 value) internal returns (bool result) {
        result = remove(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Uint8Set storage set, uint8 value) internal returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(set.slot)
            let mask := shl(and(0xff, value), 1)
            sstore(set.slot, and(result, not(mask)))
            result := iszero(iszero(and(result, mask)))
        }
    }

    /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
    function update(AddressSet storage set, address value, bool isAdd, uint256 cap)
        internal
        returns (bool)
    {
        return isAdd ? add(set, value, cap) : remove(set, value);
    }

    /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
    function update(Bytes32Set storage set, bytes32 value, bool isAdd, uint256 cap)
        internal
        returns (bool)
    {
        return isAdd ? add(set, value, cap) : remove(set, value);
    }

    /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
    function update(Uint256Set storage set, uint256 value, bool isAdd, uint256 cap)
        internal
        returns (bool)
    {
        return isAdd ? add(set, value, cap) : remove(set, value);
    }

    /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
    function update(Int256Set storage set, int256 value, bool isAdd, uint256 cap)
        internal
        returns (bool)
    {
        return isAdd ? add(set, value, cap) : remove(set, value);
    }

    /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
    function update(Uint8Set storage set, uint8 value, bool isAdd, uint256 cap)
        internal
        returns (bool)
    {
        return isAdd ? add(set, value, cap) : remove(set, value);
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(AddressSet storage set) internal view returns (address[] memory result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let zs := _ZERO_SENTINEL
            let rootPacked := sload(rootSlot)
            let n := shr(160, shl(160, rootPacked))
            result := mload(0x40)
            let o := add(0x20, result)
            let v := shr(96, rootPacked)
            mstore(o, mul(v, iszero(eq(v, zs))))
            for {} 1 {} {
                if iszero(n) {
                    if v {
                        n := 1
                        v := shr(96, sload(add(rootSlot, n)))
                        if v {
                            n := 2
                            mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
                            v := shr(96, sload(add(rootSlot, n)))
                            if v {
                                n := 3
                                mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
                            }
                        }
                    }
                    break
                }
                n := shr(1, n)
                for { let i := 1 } lt(i, n) { i := add(i, 1) } {
                    v := shr(96, sload(add(rootSlot, i)))
                    mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
                }
                break
            }
            mstore(result, n)
            mstore(0x40, add(o, shl(5, n)))
        }
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let zs := _ZERO_SENTINEL
            let n := sload(not(rootSlot))
            result := mload(0x40)
            let o := add(0x20, result)
            for {} 1 {} {
                if iszero(n) {
                    let v := sload(rootSlot)
                    if v {
                        n := 1
                        mstore(o, mul(v, iszero(eq(v, zs))))
                        v := sload(add(rootSlot, n))
                        if v {
                            n := 2
                            mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
                            v := sload(add(rootSlot, n))
                            if v {
                                n := 3
                                mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
                            }
                        }
                    }
                    break
                }
                n := shr(1, n)
                for { let i := 0 } lt(i, n) { i := add(i, 1) } {
                    let v := sload(add(rootSlot, i))
                    mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
                }
                break
            }
            mstore(result, n)
            mstore(0x40, add(o, shl(5, n)))
        }
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Uint256Set storage set) internal view returns (uint256[] memory result) {
        result = _toUints(values(_toBytes32Set(set)));
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Int256Set storage set) internal view returns (int256[] memory result) {
        result = _toInts(values(_toBytes32Set(set)));
    }

    /// @dev Returns all of the values in the set.
    function values(Uint8Set storage set) internal view returns (uint8[] memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let ptr := add(result, 0x20)
            let o := 0
            for { let packed := sload(set.slot) } packed {} {
                if iszero(and(packed, 0xffff)) {
                    o := add(o, 16)
                    packed := shr(16, packed)
                    continue
                }
                mstore(ptr, o)
                ptr := add(ptr, shl(5, and(packed, 1)))
                o := add(o, 1)
                packed := shr(1, packed)
            }
            mstore(result, shr(5, sub(ptr, add(result, 0x20))))
            mstore(0x40, ptr)
        }
    }

    /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
    function at(AddressSet storage set, uint256 i) internal view returns (address result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            result := shr(96, sload(add(rootSlot, i)))
            result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
        }
        if (i >= length(set)) revert IndexOutOfBounds();
    }

    /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
    function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) {
        result = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(add(result, i))
            result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
        }
        if (i >= length(set)) revert IndexOutOfBounds();
    }

    /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
    function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) {
        result = uint256(at(_toBytes32Set(set), i));
    }

    /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
    function at(Int256Set storage set, uint256 i) internal view returns (int256 result) {
        result = int256(uint256(at(_toBytes32Set(set), i)));
    }

    /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
    function at(Uint8Set storage set, uint256 i) internal view returns (uint8 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let packed := sload(set.slot)
            for {} 1 {
                mstore(0x00, 0x4e23d035) // `IndexOutOfBounds()`.
                revert(0x1c, 0x04)
            } {
                if iszero(lt(i, 256)) { continue }
                for { let j := 0 } iszero(eq(i, j)) {} {
                    packed := xor(packed, and(packed, add(1, not(packed))))
                    j := add(j, 1)
                }
                if iszero(packed) { continue }
                break
            }
            // Find first set subroutine, optimized for smaller bytecode size.
            let x := and(packed, add(1, not(packed)))
            let r := shl(7, iszero(iszero(shr(128, x))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            // For the lower 5 bits of the result, use a De Bruijn lookup.
            // forgefmt: disable-next-item
            result := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the root slot.
    function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
            mstore(0x00, s.slot)
            r := keccak256(0x00, 0x24)
        }
    }

    /// @dev Returns the root slot.
    function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
            mstore(0x00, s.slot)
            r := keccak256(0x00, 0x24)
        }
    }

    /// @dev Casts to a Bytes32Set.
    function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) {
        /// @solidity memory-safe-assembly
        assembly {
            c.slot := s.slot
        }
    }

    /// @dev Casts to a Bytes32Set.
    function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) {
        /// @solidity memory-safe-assembly
        assembly {
            c.slot := s.slot
        }
    }

    /// @dev Casts to a uint256 array.
    function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := a
        }
    }

    /// @dev Casts to a int256 array.
    function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := a
        }
    }
}

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

/// @notice Receiver mixin for ETH and safe-transferred ERC721 and ERC1155 tokens.
/// @author Solady (https://github.com/Vectorized/solady/blob/main/src/accounts/Receiver.sol)
///
/// @dev Note:
/// - Handles all ERC721 and ERC1155 token safety callbacks.
/// - Collapses function table gas overhead and code size.
/// - Utilizes fallback so unknown calldata will pass on.
abstract contract Receiver {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The function selector is not recognized.
    error FnSelectorNotRecognized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     RECEIVE / FALLBACK                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev For receiving ETH.
    receive() external payable virtual {}

    /// @dev Fallback function with the `receiverFallback` modifier.
    fallback() external payable virtual receiverFallback {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x3c10b94e) // `FnSelectorNotRecognized()`.
            revert(0x1c, 0x04)
        }
    }

    /// @dev Modifier for the fallback function to handle token callbacks.
    modifier receiverFallback() virtual {
        _beforeReceiverFallbackBody();
        if (_useReceiverFallbackBody()) {
            /// @solidity memory-safe-assembly
            assembly {
                let s := shr(224, calldataload(0))
                // 0x150b7a02: `onERC721Received(address,address,uint256,bytes)`.
                // 0xf23a6e61: `onERC1155Received(address,address,uint256,uint256,bytes)`.
                // 0xbc197c81: `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
                if or(eq(s, 0x150b7a02), or(eq(s, 0xf23a6e61), eq(s, 0xbc197c81))) {
                    // Assumes `mload(0x40) <= 0xffffffff` to save gas on cleaning lower bytes.
                    mstore(0x20, s) // Store `msg.sig`.
                    return(0x3c, 0x20) // Return `msg.sig`.
                }
            }
        }
        _afterReceiverFallbackBody();
        _;
    }

    /// @dev Whether we want to use the body of the `receiverFallback` modifier.
    function _useReceiverFallbackBody() internal view virtual returns (bool) {
        return true;
    }

    /// @dev Called before the body of the `receiverFallback` modifier.
    function _beforeReceiverFallbackBody() internal virtual {}

    /// @dev Called after the body of the `receiverFallback` modifier.
    function _afterReceiverFallbackBody() internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/P256.sol)
pragma solidity ^0.8.20;

import {Math} from "../math/Math.sol";
import {Errors} from "../Errors.sol";

/**
 * @dev Implementation of secp256r1 verification and recovery functions.
 *
 * The secp256r1 curve (also known as P256) is a NIST standard curve with wide support in modern devices
 * and cryptographic standards. Some notable examples include Apple's Secure Enclave and Android's Keystore
 * as well as authentication protocols like FIDO2.
 *
 * Based on the original https://github.com/itsobvioustech/aa-passkeys-wallet/blob/d3d423f28a4d8dfcb203c7fa0c47f42592a7378e/src/Secp256r1.sol[implementation of itsobvioustech] (GNU General Public License v3.0).
 * Heavily inspired in https://github.com/maxrobot/elliptic-solidity/blob/c4bb1b6e8ae89534d8db3a6b3a6b52219100520f/contracts/Secp256r1.sol[maxrobot] and
 * https://github.com/tdrerup/elliptic-curve-solidity/blob/59a9c25957d4d190eff53b6610731d81a077a15e/contracts/curves/EllipticCurve.sol[tdrerup] implementations.
 *
 * _Available since v5.1._
 */
library P256 {
    struct JPoint {
        uint256 x;
        uint256 y;
        uint256 z;
    }

    /// @dev Generator (x component)
    uint256 internal constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;
    /// @dev Generator (y component)
    uint256 internal constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;
    /// @dev P (size of the field)
    uint256 internal constant P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
    /// @dev N (order of G)
    uint256 internal constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
    /// @dev A parameter of the weierstrass equation
    uint256 internal constant A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC;
    /// @dev B parameter of the weierstrass equation
    uint256 internal constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;

    /// @dev (P + 1) / 4. Useful to compute sqrt
    uint256 private constant P1DIV4 = 0x3fffffffc0000000400000000000000000000000400000000000000000000000;

    /// @dev N/2 for excluding higher order `s` values
    uint256 private constant HALF_N = 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8;

    /**
     * @dev Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation
     * if the precompile is not available. This version should work on all chains, but requires the deployment of more
     * bytecode.
     *
     * @param h - hashed message
     * @param r - signature half R
     * @param s - signature half S
     * @param qx - public key coordinate X
     * @param qy - public key coordinate Y
     *
     * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability.
     * To flip the `s` value, compute `s = N - s`.
     */
    function verify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
        (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy);
        return supported ? valid : verifySolidity(h, r, s, qx, qy);
    }

    /**
     * @dev Same as {verify}, but it will revert if the required precompile is not available.
     *
     * Make sure any logic (code or precompile) deployed at that address is the expected one,
     * otherwise the returned value may be misinterpreted as a positive boolean.
     */
    function verifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
        (bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy);
        if (supported) {
            return valid;
        } else {
            revert Errors.MissingPrecompile(address(0x100));
        }
    }

    /**
     * @dev Same as {verify}, but it will return false if the required precompile is not available.
     */
    function _tryVerifyNative(
        bytes32 h,
        bytes32 r,
        bytes32 s,
        bytes32 qx,
        bytes32 qy
    ) private view returns (bool valid, bool supported) {
        if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) {
            return (false, true); // signature is invalid, and its not because the precompile is missing
        }

        (bool success, bytes memory returndata) = address(0x100).staticcall(abi.encode(h, r, s, qx, qy));
        return (success && returndata.length == 0x20) ? (abi.decode(returndata, (bool)), true) : (false, false);
    }

    /**
     * @dev Same as {verify}, but only the Solidity implementation is used.
     */
    function verifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
        if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) {
            return false;
        }

        JPoint[16] memory points = _preComputeJacobianPoints(uint256(qx), uint256(qy));
        uint256 w = Math.invModPrime(uint256(s), N);
        uint256 u1 = mulmod(uint256(h), w, N);
        uint256 u2 = mulmod(uint256(r), w, N);
        (uint256 x, ) = _jMultShamir(points, u1, u2);
        return ((x % N) == uint256(r));
    }

    /**
     * @dev Public key recovery
     *
     * @param h - hashed message
     * @param v - signature recovery param
     * @param r - signature half R
     * @param s - signature half S
     *
     * IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability.
     * To flip the `s` value, compute `s = N - s` and `v = 1 - v` if (`v = 0 | 1`).
     */
    function recovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal view returns (bytes32 x, bytes32 y) {
        if (!_isProperSignature(r, s) || v > 1) {
            return (0, 0);
        }

        uint256 p = P; // cache P on the stack
        uint256 rx = uint256(r);
        uint256 ry2 = addmod(mulmod(addmod(mulmod(rx, rx, p), A, p), rx, p), B, p); // weierstrass equation y² = x³ + a.x + b
        uint256 ry = Math.modExp(ry2, P1DIV4, p); // This formula for sqrt work because P ≡ 3 (mod 4)
        if (mulmod(ry, ry, p) != ry2) return (0, 0); // Sanity check
        if (ry % 2 != v) ry = p - ry;

        JPoint[16] memory points = _preComputeJacobianPoints(rx, ry);
        uint256 w = Math.invModPrime(uint256(r), N);
        uint256 u1 = mulmod(N - (uint256(h) % N), w, N);
        uint256 u2 = mulmod(uint256(s), w, N);
        (uint256 xU, uint256 yU) = _jMultShamir(points, u1, u2);
        return (bytes32(xU), bytes32(yU));
    }

    /**
     * @dev Checks if (x, y) are valid coordinates of a point on the curve.
     * In particular this function checks that x < P and y < P.
     */
    function isValidPublicKey(bytes32 x, bytes32 y) internal pure returns (bool result) {
        assembly ("memory-safe") {
            let p := P
            let lhs := mulmod(y, y, p) // y^2
            let rhs := addmod(mulmod(addmod(mulmod(x, x, p), A, p), x, p), B, p) // ((x^2 + a) * x) + b = x^3 + ax + b
            result := and(and(lt(x, p), lt(y, p)), eq(lhs, rhs)) // Should conform with the Weierstrass equation
        }
    }

    /**
     * @dev Checks if (r, s) is a proper signature.
     * In particular, this checks that `s` is in the "lower-range", making the signature non-malleable.
     */
    function _isProperSignature(bytes32 r, bytes32 s) private pure returns (bool) {
        return uint256(r) > 0 && uint256(r) < N && uint256(s) > 0 && uint256(s) <= HALF_N;
    }

    /**
     * @dev Reduce from jacobian to affine coordinates
     * @param jx - jacobian coordinate x
     * @param jy - jacobian coordinate y
     * @param jz - jacobian coordinate z
     * @return ax - affine coordinate x
     * @return ay - affine coordinate y
     */
    function _affineFromJacobian(uint256 jx, uint256 jy, uint256 jz) private view returns (uint256 ax, uint256 ay) {
        if (jz == 0) return (0, 0);
        uint256 p = P; // cache P on the stack
        uint256 zinv = Math.invModPrime(jz, p);
        assembly ("memory-safe") {
            let zzinv := mulmod(zinv, zinv, p)
            ax := mulmod(jx, zzinv, p)
            ay := mulmod(jy, mulmod(zzinv, zinv, p), p)
        }
    }

    /**
     * @dev Point addition on the jacobian coordinates
     * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-1998-cmo-2
     *
     * Note that:
     *
     * - `addition-add-1998-cmo-2` doesn't support identical input points. This version is modified to use
     * the `h` and `r` values computed by `addition-add-1998-cmo-2` to detect identical inputs, and fallback to
     * `doubling-dbl-1998-cmo-2` if needed.
     * - if one of the points is at infinity (i.e. `z=0`), the result is undefined.
     */
    function _jAdd(
        JPoint memory p1,
        uint256 x2,
        uint256 y2,
        uint256 z2
    ) private pure returns (uint256 rx, uint256 ry, uint256 rz) {
        assembly ("memory-safe") {
            let p := P
            let z1 := mload(add(p1, 0x40))
            let zz1 := mulmod(z1, z1, p) // zz1 = z1²
            let s1 := mulmod(mload(add(p1, 0x20)), mulmod(mulmod(z2, z2, p), z2, p), p) // s1 = y1*z2³
            let r := addmod(mulmod(y2, mulmod(zz1, z1, p), p), sub(p, s1), p) // r = s2-s1 = y2*z1³-s1 = y2*z1³-y1*z2³
            let u1 := mulmod(mload(p1), mulmod(z2, z2, p), p) // u1 = x1*z2²
            let h := addmod(mulmod(x2, zz1, p), sub(p, u1), p) // h = u2-u1 = x2*z1²-u1 = x2*z1²-x1*z2²

            // detect edge cases where inputs are identical
            switch and(iszero(r), iszero(h))
            // case 0: points are different
            case 0 {
                let hh := mulmod(h, h, p) // h²

                // x' = r²-h³-2*u1*h²
                rx := addmod(
                    addmod(mulmod(r, r, p), sub(p, mulmod(h, hh, p)), p),
                    sub(p, mulmod(2, mulmod(u1, hh, p), p)),
                    p
                )
                // y' = r*(u1*h²-x')-s1*h³
                ry := addmod(
                    mulmod(r, addmod(mulmod(u1, hh, p), sub(p, rx), p), p),
                    sub(p, mulmod(s1, mulmod(h, hh, p), p)),
                    p
                )
                // z' = h*z1*z2
                rz := mulmod(h, mulmod(z1, z2, p), p)
            }
            // case 1: points are equal
            case 1 {
                let x := x2
                let y := y2
                let z := z2
                let yy := mulmod(y, y, p)
                let zz := mulmod(z, z, p)
                let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴
                let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y²

                // x' = t = m²-2*s
                rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)

                // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴
                // cut the computation to avoid stack too deep
                let rytmp1 := sub(p, mulmod(8, mulmod(yy, yy, p), p)) // -8*y⁴
                let rytmp2 := addmod(s, sub(p, rx), p) // s-x'
                ry := addmod(mulmod(m, rytmp2, p), rytmp1, p) // m*(s-x')-8*y⁴

                // z' = 2*y*z
                rz := mulmod(2, mulmod(y, z, p), p)
            }
        }
    }

    /**
     * @dev Point doubling on the jacobian coordinates
     * Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2
     */
    function _jDouble(uint256 x, uint256 y, uint256 z) private pure returns (uint256 rx, uint256 ry, uint256 rz) {
        assembly ("memory-safe") {
            let p := P
            let yy := mulmod(y, y, p)
            let zz := mulmod(z, z, p)
            let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴
            let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y²

            // x' = t = m²-2*s
            rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)
            // y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴
            ry := addmod(mulmod(m, addmod(s, sub(p, rx), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)
            // z' = 2*y*z
            rz := mulmod(2, mulmod(y, z, p), p)
        }
    }

    /**
     * @dev Compute G·u1 + P·u2 using the precomputed points for G and P (see {_preComputeJacobianPoints}).
     *
     * Uses Strauss Shamir trick for EC multiplication
     * https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method
     *
     * We optimize this for 2 bits at a time rather than a single bit. The individual points for a single pass are
     * precomputed. Overall this reduces the number of additions while keeping the same number of
     * doublings
     */
    function _jMultShamir(
        JPoint[16] memory points,
        uint256 u1,
        uint256 u2
    ) private view returns (uint256 rx, uint256 ry) {
        uint256 x = 0;
        uint256 y = 0;
        uint256 z = 0;
        unchecked {
            for (uint256 i = 0; i < 128; ++i) {
                if (z > 0) {
                    (x, y, z) = _jDouble(x, y, z);
                    (x, y, z) = _jDouble(x, y, z);
                }
                // Read 2 bits of u1, and 2 bits of u2. Combining the two gives the lookup index in the table.
                uint256 pos = ((u1 >> 252) & 0xc) | ((u2 >> 254) & 0x3);
                // Points that have z = 0 are points at infinity. They are the additive 0 of the group
                // - if the lookup point is a 0, we can skip it
                // - otherwise:
                //   - if the current point (x, y, z) is 0, we use the lookup point as our new value (0+P=P)
                //   - if the current point (x, y, z) is not 0, both points are valid and we can use `_jAdd`
                if (points[pos].z != 0) {
                    if (z == 0) {
                        (x, y, z) = (points[pos].x, points[pos].y, points[pos].z);
                    } else {
                        (x, y, z) = _jAdd(points[pos], x, y, z);
                    }
                }
                u1 <<= 2;
                u2 <<= 2;
            }
        }
        return _affineFromJacobian(x, y, z);
    }

    /**
     * @dev Precompute a matrice of useful jacobian points associated with a given P. This can be seen as a 4x4 matrix
     * that contains combination of P and G (generator) up to 3 times each. See the table below:
     *
     * ┌────┬─────────────────────┐
     * │  i │  0    1     2     3 │
     * ├────┼─────────────────────┤
     * │  0 │  0    p    2p    3p │
     * │  4 │  g  g+p  g+2p  g+3p │
     * │  8 │ 2g 2g+p 2g+2p 2g+3p │
     * │ 12 │ 3g 3g+p 3g+2p 3g+3p │
     * └────┴─────────────────────┘
     *
     * Note that `_jAdd` (and thus `_jAddPoint`) does not handle the case where one of the inputs is a point at
     * infinity (z = 0). However, we know that since `N ≡ 1 mod 2` and `N ≡ 1 mod 3`, there is no point P such that
     * 2P = 0 or 3P = 0. This guarantees that g, 2g, 3g, p, 2p, 3p are all non-zero, and that all `_jAddPoint` calls
     * have valid inputs.
     */
    function _preComputeJacobianPoints(uint256 px, uint256 py) private pure returns (JPoint[16] memory points) {
        points[0x00] = JPoint(0, 0, 0); // 0,0
        points[0x01] = JPoint(px, py, 1); // 1,0 (p)
        points[0x04] = JPoint(GX, GY, 1); // 0,1 (g)
        points[0x02] = _jDoublePoint(points[0x01]); // 2,0 (2p)
        points[0x08] = _jDoublePoint(points[0x04]); // 0,2 (2g)
        points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (p+2p = 3p)
        points[0x05] = _jAddPoint(points[0x01], points[0x04]); // 1,1 (p+g)
        points[0x06] = _jAddPoint(points[0x02], points[0x04]); // 2,1 (2p+g)
        points[0x07] = _jAddPoint(points[0x03], points[0x04]); // 3,1 (3p+g)
        points[0x09] = _jAddPoint(points[0x01], points[0x08]); // 1,2 (p+2g)
        points[0x0a] = _jAddPoint(points[0x02], points[0x08]); // 2,2 (2p+2g)
        points[0x0b] = _jAddPoint(points[0x03], points[0x08]); // 3,2 (3p+2g)
        points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g = 3g)
        points[0x0d] = _jAddPoint(points[0x01], points[0x0c]); // 1,3 (p+3g)
        points[0x0e] = _jAddPoint(points[0x02], points[0x0c]); // 2,3 (2p+3g)
        points[0x0f] = _jAddPoint(points[0x03], points[0x0c]); // 3,3 (3p+3g)
    }

    function _jAddPoint(JPoint memory p1, JPoint memory p2) private pure returns (JPoint memory) {
        (uint256 x, uint256 y, uint256 z) = _jAdd(p1, p2.x, p2.y, p2.z);
        return JPoint(x, y, z);
    }

    function _jDoublePoint(JPoint memory p) private pure returns (JPoint memory) {
        (uint256 x, uint256 y, uint256 z) = _jDouble(p.x, p.y, p.z);
        return JPoint(x, y, z);
    }
}

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

import "./PackedUserOperation.sol";

interface IAccount {
    /**
     * Validate user's signature and nonce
     * the entryPoint will make the call to the recipient only if this validation call returns successfully.
     * signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
     * This allows making a "simulation call" without a valid signature
     * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
     *
     * @dev Must validate caller is the entryPoint.
     *      Must validate the signature and nonce
     * @param userOp              - The operation that is about to be executed.
     * @param userOpHash          - Hash of the user's request data. can be used as the basis for signature.
     * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint.
     *                              This is the minimum amount to transfer to the sender(entryPoint) to be
     *                              able to make the call. The excess is left as a deposit in the entrypoint
     *                              for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()".
     *                              In case there is a paymaster in the request (or the current deposit is high
     *                              enough), this value will be zero.
     * @return validationData       - Packaged ValidationData structure. use `_packValidationData` and
     *                              `_unpackValidationData` to encode and decode.
     *                              <20-byte> aggregatorOrSigFail - 0 for valid signature, 1 to mark signature failure,
     *                                 otherwise, an address of an "aggregator" contract.
     *                              <6-byte> validUntil - Last timestamp this operation is valid at, or 0 for "indefinitely"
     *                              <6-byte> validAfter - First timestamp this operation is valid
     *                                                    If an account doesn't use time-range, it is enough to
     *                                                    return SIG_VALIDATION_FAILED value (1) for signature failure.
     *                              Note that the validation code cannot use block.timestamp (or block.number) directly.
     */
    function validateUserOp(
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 missingAccountFunds
    ) external returns (uint256 validationData);
}

File 7 of 63 : PackedUserOperation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

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

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

/// @title IERC1271
interface IERC1271 {
    /// @notice Validates the `signature` against the given `hash`.
    /// @dev Supports the following signature workflows:
    /// - 64 or 65-byte ECDSA signatures from address(this)
    /// - Nested typed data signatures as defined by ERC-7739
    /// - Nested personal signatures as defined by ERC-7739
    /// @dev A wrappedSignature contains a keyHash, signature, and any optional hook data
    ///      `signature` can contain extra fields used for webauthn verification or ERC7739 nested typed data verification
    /// @dev An unwrapped signature is only valid for the root key. However, the root key can also sign a 7739 rehashed signature.
    /// It is possible for an unwrapped signature from the root key to be replayed IF the root key is registered on another wallet, not this one, and that wallet
    /// does not enforce defensive rehashing for its keys. If this is a concern, use a 7739 wrapped signature for the root key.
    /// @return result `0x1626ba7e` if validation succeeded, else `0xffffffff`.
    function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4);
}

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

interface IERC7821 {
    /// @dev Thrown when an unsupported execution mode is provided.
    error UnsupportedExecutionMode();

    /// @dev Executes a batched call.
    /// @dev The mode is checked with strict equality in the implementation and only supports two mode types.
    /// @param mode The mode to execute the batched call in.
    /// @param executionData The data to execute the batched call with.
    function execute(bytes32 mode, bytes calldata executionData) external payable;

    /// @dev Provided for execution mode support detection.
    /// @dev This returns true for the BATCHED_CALL "0x010...00" and BATCHED_CALL_CAN_REVERT "0x01010...00" modes.
    function supportsExecutionMode(bytes32 mode) external view returns (bool result);
}

File 10 of 63 : IHook.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IValidationHook} from "./IValidationHook.sol";
import {IExecutionHook} from "./IExecutionHook.sol";

/// @title IHook
/// @notice Unified interface for validation and execution hooks
/// @dev Hooks may implement both interfaces
interface IHook is IValidationHook, IExecutionHook {}

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

import {Key} from "../libraries/KeyLib.sol";
import {Settings} from "../libraries/SettingsLib.sol";

interface IKeyManagement {
    /// @dev Emitted when a key is registered.
    event Registered(bytes32 indexed keyHash, Key key);

    /// @dev Emitted when a key is revoked.
    event Revoked(bytes32 indexed keyHash);

    /// @dev Emitted when a key's settings are updated.
    event KeySettingsUpdated(bytes32 indexed keyHash, Settings settings);

    /// @dev The key does not exist.
    error KeyDoesNotExist();

    /// @dev The key has expired.
    error KeyExpired(uint40 expiration);

    /// @dev Cannot apply restrictions to the root key.
    error CannotUpdateRootKey();

    /// @dev Cannot register the root key.
    error CannotRegisterRootKey();

    /// @dev Only admin keys can self-call.
    error OnlyAdminCanSelfCall();

    /// @dev Registers the `key`.
    function register(Key memory key) external;

    /// @dev Revokes the key with the `keyHash`.
    function revoke(bytes32 keyHash) external;

    /// @dev Updates the `keyHash` with the `keySettings`.
    function update(bytes32 keyHash, Settings keySettings) external;

    /// @dev Returns the number of registered keys.
    function keyCount() external view returns (uint256);

    /// @dev Returns the key at the `i`-th position in the key list.
    function keyAt(uint256 i) external view returns (Key memory);

    /// @dev Returns the key corresponding to the `keyHash`. Reverts if the key does not exist.
    function getKey(bytes32 keyHash) external view returns (Key memory key);

    /// @dev Returns the settings for the `keyHash`.
    function getKeySettings(bytes32 keyHash) external view returns (Settings);

    /// @dev Returns whether the key is actively registered on the contract.
    function isRegistered(bytes32 keyHash) external view returns (bool);
}

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

import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import {IERC1271} from "./IERC1271.sol";
import {IERC4337Account} from "./IERC4337Account.sol";
import {IERC7201} from "./IERC7201.sol";
import {IERC7821} from "./IERC7821.sol";
import {IERC7914} from "./IERC7914.sol";
import {IEIP712} from "./IEIP712.sol";
import {IKeyManagement} from "./IKeyManagement.sol";
import {IMulticall} from "./IMulticall.sol";
import {INonceManager} from "./INonceManager.sol";
import {BatchedCall} from "../libraries/BatchedCallLib.sol";
import {SignedBatchedCall} from "../libraries/SignedBatchedCallLib.sol";

/// A non-upgradeable contract that can be delegated to with a 7702 delegation transaction.
/// This implementation supports:
/// ERC-4337 relayable userOps, with version v0.8.0 of the Entrypoint contract.
/// ERC-7821 batched actions
/// EIP-712 typed data signature verification
/// ERC-7201 compliant storage use
/// ERC-1271 compliant signature verification
/// ERC-7914 transfer from native
/// Alternative key management and verification
/// Multicall
interface ICalibur is
    IKeyManagement,
    IERC4337Account,
    IERC7821,
    IERC1271,
    IEIP712,
    IERC5267,
    IERC7201,
    IERC7914,
    INonceManager,
    IMulticall
{
    /// @notice Generic error to bubble up errors from batched calls
    /// @param reason The revert data from the inner call
    error CallFailed(bytes reason);

    /// @dev Used when internally verifying signatures over batched calls
    error InvalidSignature();

    /// @dev Thrown when the signature has expired
    error SignatureExpired();

    /// @notice Execute entrypoint for trusted callers
    /// @dev This function is only callable by this account or an admin key
    /// @param batchedCall The batched call to execute
    function execute(BatchedCall memory batchedCall) external payable;

    /// @notice Execute entrypoint for relayed batched calls
    /// @param signedBatchedCall The signed batched call to execute
    /// @param wrappedSignature The signature along with any optional hook data, equivalent to abi.encode(bytes, bytes)
    function execute(SignedBatchedCall memory signedBatchedCall, bytes memory wrappedSignature) external payable;
}

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

import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {IEIP712} from "./interfaces/IEIP712.sol";
import {BaseAuthorization} from "./BaseAuthorization.sol";
import {PrefixedSaltLib} from "./libraries/PrefixedSaltLib.sol";

/// @title EIP712
/// @dev This contract does not cache the domain separator and instead calculates it on the fly
///      since it will change when delegated to or when the salt is updated.
/// @notice It is not compatible with use by proxy contracts since the domain name and version are cached on deployment.
contract EIP712 is IEIP712, IERC5267, BaseAuthorization {
    using PrefixedSaltLib for uint96;
    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)")`.

    bytes32 internal constant _DOMAIN_TYPEHASH = 0xd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472;

    /// @dev Cached name and version hashes for cheaper runtime gas costs.
    bytes32 private immutable _cachedNameHash;
    bytes32 private immutable _cachedVersionHash;
    address private immutable _cachedImplementation;

    /// @dev Any prefix to be added to the salt. This can be updated by the owner or an admin but it defaults to 0.
    uint96 private _saltPrefix;

    constructor() {
        string memory name;
        string memory version;
        (name, version) = _domainNameAndVersion();
        _cachedNameHash = keccak256(bytes(name));
        _cachedVersionHash = keccak256(bytes(version));
        _cachedImplementation = address(this);
    }

    /// @notice Returns information about the `EIP712Domain` used to create EIP-712 compliant hashes.
    ///
    /// @dev Follows ERC-5267 (see https://eips.ethereum.org/EIPS/eip-5267).
    ///
    /// @return fields The bitmap of used fields.
    /// @return name The value of the `EIP712Domain.name` field.
    /// @return version The value of the `EIP712Domain.version` field.
    /// @return chainId The value of the `EIP712Domain.chainId` field.
    /// @return verifyingContract The value of the `EIP712Domain.verifyingContract` field.
    /// @return salt The value of the `EIP712Domain.salt` field.
    /// @return extensions The list of EIP numbers, that extends EIP-712 with new domain fields.
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        fields = hex"1f"; // `0b11111`.
        (name, version) = _domainNameAndVersion();
        chainId = block.chainid;
        verifyingContract = address(this);
        salt = _saltPrefix.pack(_cachedImplementation);
        extensions = new uint256[](0);
    }

    /// @inheritdoc IEIP712
    function domainBytes() public view returns (bytes memory) {
        // _eip712Domain().fields and _eip712Domain().extensions are not used
        (,,, uint256 chainId, address verifyingContract, bytes32 salt,) = eip712Domain();
        return abi.encode(_cachedNameHash, _cachedVersionHash, chainId, verifyingContract, salt);
    }

    /// @inheritdoc IEIP712
    function domainSeparator() public view returns (bytes32) {
        return keccak256(
            abi.encode(
                _DOMAIN_TYPEHASH,
                _cachedNameHash,
                _cachedVersionHash,
                block.chainid,
                address(this),
                _saltPrefix.pack(_cachedImplementation)
            )
        );
    }

    /// @inheritdoc IEIP712
    function hashTypedData(bytes32 hash) public view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(domainSeparator(), hash);
    }

    /// @inheritdoc IEIP712
    function updateSalt(uint96 prefix) external onlyThis {
        if (prefix != _saltPrefix) {
            _saltPrefix = prefix;
            // per EIP-5267, emit an event to notify that the domain separator has changed
            emit EIP712DomainChanged();
        }
    }

    /// @notice Returns the domain name and version to use when creating EIP-712 signatures.
    /// @return name    The user readable name of signing domain.
    /// @return version The current major version of the signing domain.
    function _domainNameAndVersion() internal pure returns (string memory name, string memory version) {
        return ("Calibur", "1.0.0");
    }
}

File 14 of 63 : ERC1271.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IERC1271} from "./interfaces/IERC1271.sol";

/// @title ERC-1271
/// @notice Abstract ERC1271 implementation which supports nested EIP-712 workflows as defined by ERC-7739
abstract contract ERC1271 is IERC1271 {
    /// @dev The magic value returned by `isValidSignature()` if the signature is valid.
    bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e;
    /// @dev The magic value returned by `isValidSignature()` if the signature is invalid.
    bytes4 internal constant _1271_INVALID_VALUE = 0xffffffff;

    /// @inheritdoc IERC1271
    function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4);
}

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

import {IERC4337Account} from "./interfaces/IERC4337Account.sol";
import {BaseAuthorization} from "./BaseAuthorization.sol";
import {EntrypointLib} from "./libraries/EntrypointLib.sol";
import {Static} from "./libraries/Static.sol";

/// @title ERC4337Account
/// @notice A base contract which allows for the entrypoint to have a default value that can be updated
abstract contract ERC4337Account is IERC4337Account, BaseAuthorization {
    using EntrypointLib for *;

    /// ERC-4337 defined constants
    uint256 internal constant SIG_VALIDATION_SUCCEEDED = 0;
    uint256 internal constant SIG_VALIDATION_FAILED = 1;

    /// @notice The cached entrypoint address
    uint256 internal _CACHED_ENTRYPOINT;

    modifier onlyEntryPoint() {
        if (msg.sender != ENTRY_POINT()) revert NotEntryPoint();
        _;
    }

    /// @inheritdoc IERC4337Account
    function updateEntryPoint(address entryPoint) external onlyThis {
        _CACHED_ENTRYPOINT = entryPoint.pack();
        emit EntryPointUpdated(entryPoint);
    }

    /// @inheritdoc IERC4337Account
    function ENTRY_POINT() public view override returns (address) {
        uint256 _entryPoint = _CACHED_ENTRYPOINT;
        return _entryPoint.isOverriden() ? _entryPoint.unpack() : Static.ENTRY_POINT_V_0_8;
    }

    // https://github.com/coinbase/smart-wallet/blob/main/src/CoinbaseSmartWallet.sol#L100
    function _payEntryPoint(uint256 missingAccountFunds) internal {
        assembly ("memory-safe") {
            if missingAccountFunds {
                // Ignore failure (it's EntryPoint's job to verify, not the account's).
                pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00))
            }
        }
    }
}

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

import {IERC7201} from "./interfaces/IERC7201.sol";

/// @title ERC-7201
/// @notice Public getters for the ERC7201 calculated storage root, namespace, and version
contract ERC7201 is IERC7201 {
    /// @notice The calculated storage root of the contract according to ERC7201
    /// @dev The literal value is used in CaliburEntry.sol as it must be constant at compile time
    /// equivalent to keccak256(abi.encode(uint256(keccak256("Uniswap.Calibur.1.0.0")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 public constant CUSTOM_STORAGE_ROOT = 0x3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600;

    /// @notice Returns the namespace and version of the contract
    function namespaceAndVersion() external pure returns (string memory) {
        return "Uniswap.Calibur.1.0.0";
    }
}

File 17 of 63 : ERC7821.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IERC7821} from "./interfaces/IERC7821.sol";
import {ModeDecoder} from "./libraries/ModeDecoder.sol";

/// @title ERC7821
/// @notice A base contract that implements the ERC7821 interface
/// @dev This contract supports only the Single Batch mode defined in the specification. See IERC7821.supportsExecutionMode() for more details.
///      We do NOT support the following ERC-7821 execution modes:
///      - `0x01000000000078210001...`: Single batch with optional `opData`.
///      - `0x01000000000078210002...`: Batch of batches
abstract contract ERC7821 is IERC7821 {
    using ModeDecoder for bytes32;

    /// @inheritdoc IERC7821
    function supportsExecutionMode(bytes32 mode) external pure override returns (bool result) {
        return mode.isBatchedCall();
    }
}

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

import {IERC7914} from "./interfaces/IERC7914.sol";
import {TransientNativeAllowance} from "./libraries/TransientNativeAllowance.sol";
import {BaseAuthorization} from "./BaseAuthorization.sol";

/// @title ERC-7914
/// @notice Abstract ERC-7914 implementation with support for transient allowances
/// @dev this ERC is not finalized and is subject to change in the future
/// https://github.com/ethereum/ERCs/blob/8380220418521ff1995445cff5ca1d0e496a3d2d/ERCS/erc-7914.md
abstract contract ERC7914 is IERC7914, BaseAuthorization {
    mapping(address spender => uint256 allowance) public nativeAllowance;

    /// @inheritdoc IERC7914
    function approveNative(address spender, uint256 amount) external onlyThis returns (bool) {
        nativeAllowance[spender] = amount;
        emit ApproveNative(address(this), spender, amount);
        return true;
    }

    /// @inheritdoc IERC7914
    function approveNativeTransient(address spender, uint256 amount) external onlyThis returns (bool) {
        TransientNativeAllowance.set(spender, amount);
        emit ApproveNativeTransient(address(this), spender, amount);
        return true;
    }

    /// @inheritdoc IERC7914
    function transferFromNative(address from, address recipient, uint256 amount) external returns (bool) {
        if (amount == 0) return true;
        _transferFrom(from, recipient, amount, false);
        emit TransferFromNative(address(this), recipient, amount);
        return true;
    }

    /// @inheritdoc IERC7914
    function transferFromNativeTransient(address from, address recipient, uint256 amount) external returns (bool) {
        if (amount == 0) return true;
        _transferFrom(from, recipient, amount, true);
        emit TransferFromNativeTransient(address(this), recipient, amount);
        return true;
    }

    /// @inheritdoc IERC7914
    function transientNativeAllowance(address spender) public view returns (uint256) {
        return TransientNativeAllowance.get(spender);
    }

    /// @dev Internal function to validate and execute transfers
    /// @param from The address to transfer from
    /// @param recipient The address to receive the funds
    /// @param amount The amount to transfer
    /// @param isTransient Whether this is transient allowance or not
    function _transferFrom(address from, address recipient, uint256 amount, bool isTransient) internal {
        // Validate inputs
        if (from != address(this)) revert IncorrectSender();

        // Check allowance
        uint256 currentAllowance = isTransient ? transientNativeAllowance(msg.sender) : nativeAllowance[msg.sender];
        if (currentAllowance < amount) revert AllowanceExceeded();

        // Update allowance
        if (currentAllowance < type(uint256).max) {
            uint256 newAllowance;
            unchecked {
                newAllowance = currentAllowance - amount;
            }
            if (isTransient) {
                TransientNativeAllowance.set(msg.sender, newAllowance);
            } else {
                nativeAllowance[msg.sender] = newAllowance;
                emit NativeAllowanceUpdated(msg.sender, newAllowance);
            }
        }

        // Execute transfer
        (bool success,) = payable(recipient).call{value: amount}("");
        if (!success) {
            revert TransferNativeFailed();
        }
    }
}

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

import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {ERC7739Utils} from "./libraries/ERC7739Utils.sol";
import {Key, KeyLib} from "./libraries/KeyLib.sol";
import {WrappedSignatureLib} from "./libraries/WrappedSignatureLib.sol";

/// @title ERC7739
/// @notice An abstract contract that implements the ERC-7739 standard
/// @notice This contract assumes that all data verified through ERC-1271 `isValidSignature` implements the defensive nested hashing scheme defined in EIP-7739
/// @dev See https://eips.ethereum.org/EIPS/eip-7739
abstract contract ERC7739 {
    using WrappedSignatureLib for bytes;
    using ERC7739Utils for *;
    using KeyLib for Key;

    /// @notice Verifies that the claimed contentsHash hashed with the app's separator matches the isValidSignature provided data
    /// @dev This is a necessary check to ensure that the contentsHash and appSeparator provided in the signature are correct
    /// @param appSeparator The app's domain separator
    /// @param hash The data provided in `isValidSignature`
    /// @param contentsHash The hash of the contents, i.e. hashStruct(contents)
    function _callerHashMatchesReconstructedHash(bytes32 appSeparator, bytes32 hash, bytes32 contentsHash)
        private
        pure
        returns (bool)
    {
        return hash == MessageHashUtils.toTypedDataHash(appSeparator, contentsHash);
    }

    /// @notice Decodes the data for TypedDataSign and verifies the signature against the key over the hash
    /// @dev Performs the required checks per the ERC-7739 spec:
    /// - contentsName and contentsType are not empty
    /// - The reconstructed hash matches the hash passed in via isValidSignature
    function _isValidTypedDataSig(
        Key memory key,
        bytes32 digest,
        bytes memory domainBytes,
        bytes calldata wrappedSignature
    ) internal view returns (bool) {
        (bytes calldata signature, bytes32 appSeparator, bytes32 contentsHash, string calldata contentsDescr) =
            wrappedSignature.decodeAsTypedDataSig();

        if (!_callerHashMatchesReconstructedHash(appSeparator, digest, contentsHash)) return false;

        (string calldata contentsName, string calldata contentsType) = contentsDescr.decodeContentsDescr();
        // For safety, ERC-7739 recommends to treat the signature as invalid if either the contentsName or contentsType are empty
        if (bytes(contentsName).length == 0 || bytes(contentsType).length == 0) return false;

        bytes32 nestedDigest =
            contentsHash.toNestedTypedDataSignHash(domainBytes, appSeparator, contentsName, contentsType);

        return key.verify(nestedDigest, signature);
    }

    /// @notice Verifies a personal sign signature against the key over the hash
    function _isValidNestedPersonalSig(
        Key memory key,
        bytes32 digest,
        bytes32 domainSeparator,
        bytes calldata signature
    ) internal view returns (bool) {
        return key.verify(digest.toPersonalSignTypedDataHash(domainSeparator), signature);
    }
}

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

import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
import {IKeyManagement} from "./interfaces/IKeyManagement.sol";
import {BaseAuthorization} from "./BaseAuthorization.sol";
import {Key, KeyLib} from "./libraries/KeyLib.sol";
import {Settings, SettingsLib} from "./libraries/SettingsLib.sol";

/// @dev A base contract for managing keys
abstract contract KeyManagement is IKeyManagement, BaseAuthorization {
    using EnumerableSetLib for EnumerableSetLib.Bytes32Set;
    using KeyLib for *;
    using SettingsLib for Settings;

    EnumerableSetLib.Bytes32Set public keyHashes;
    mapping(bytes32 keyHash => bytes encodedKey) private keyStorage;
    mapping(bytes32 keyHash => Settings settings) private keySettings;

    /// @inheritdoc IKeyManagement
    function register(Key memory key) external onlyThis {
        if (key.isRootKey()) revert CannotRegisterRootKey();

        bytes32 keyHash = key.hash();
        keyStorage[keyHash] = abi.encode(key);
        keyHashes.add(keyHash);

        emit Registered(keyHash, key);
    }

    /// @inheritdoc IKeyManagement
    function update(bytes32 keyHash, Settings settings) external onlyThis {
        if (keyHash.isRootKey()) revert CannotUpdateRootKey();
        if (!isRegistered(keyHash)) revert KeyDoesNotExist();
        keySettings[keyHash] = settings;
        emit KeySettingsUpdated(keyHash, settings);
    }

    /// @inheritdoc IKeyManagement
    function revoke(bytes32 keyHash) external onlyThis {
        if (!keyHashes.remove(keyHash)) revert KeyDoesNotExist();
        delete keyStorage[keyHash];
        keySettings[keyHash] = SettingsLib.DEFAULT;

        emit Revoked(keyHash);
    }

    /// @inheritdoc IKeyManagement
    function keyCount() external view returns (uint256) {
        return keyHashes.length();
    }

    /// @inheritdoc IKeyManagement
    function keyAt(uint256 i) external view returns (Key memory) {
        return getKey(keyHashes.at(i));
    }

    /// @inheritdoc IKeyManagement
    function getKey(bytes32 keyHash) public view returns (Key memory) {
        if (keyHash.isRootKey()) return KeyLib.toRootKey();
        if (isRegistered(keyHash)) return abi.decode(keyStorage[keyHash], (Key));
        revert KeyDoesNotExist();
    }

    /// @inheritdoc IKeyManagement
    function getKeySettings(bytes32 keyHash) public view returns (Settings) {
        if (keyHash.isRootKey()) return SettingsLib.ROOT_KEY_SETTINGS;
        if (isRegistered(keyHash)) return keySettings[keyHash];
        revert KeyDoesNotExist();
    }

    /// @inheritdoc IKeyManagement
    function isRegistered(bytes32 keyHash) public view returns (bool) {
        return keyHashes.contains(keyHash);
    }

    /// @notice Reverts if the key settings are expired
    function _checkExpiry(Settings settings) internal view {
        (bool isExpired, uint40 expiry) = settings.isExpired();
        if (isExpired) revert IKeyManagement.KeyExpired(expiry);
    }

    /// @notice Check if the keyHash is the root key or a registered, unexpired key
    function _isOwnerOrValidKey(bytes32 keyHash) internal view returns (bool) {
        if (keyHash.isRootKey()) return true;
        if (!isRegistered(keyHash)) return false;
        (bool isExpired,) = keySettings[keyHash].isExpired();
        return !isExpired;
    }
}

File 21 of 63 : Multicall.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IMulticall} from "./interfaces/IMulticall.sol";

/// @title Multicall
/// @notice Enables calling multiple methods in a single call to the contract
abstract contract Multicall is IMulticall {
    /// @inheritdoc IMulticall
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // bubble up the revert reason
                assembly {
                    revert(add(result, 0x20), mload(result))
                }
            }

            results[i] = result;
        }
    }
}

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

import {INonceManager} from "./interfaces/INonceManager.sol";
import {BaseAuthorization} from "./BaseAuthorization.sol";

/// @title NonceManager
/// @notice A contract that manages nonces to prevent replay attacks
abstract contract NonceManager is INonceManager, BaseAuthorization {
    mapping(uint256 key => uint256 seq) public nonceSequenceNumber;

    /// @inheritdoc INonceManager
    function invalidateNonce(uint256 newNonce) external onlyThis {
        uint192 key = uint192(newNonce >> 64);
        uint64 currentSeq = uint64(nonceSequenceNumber[key]);
        uint64 targetSeq = uint64(newNonce);
        if (targetSeq <= currentSeq) revert InvalidNonce();
        // Limit the amount of nonces that can be invalidated in one transaction.
        unchecked {
            uint64 delta = targetSeq - currentSeq;
            if (delta > type(uint16).max) revert ExcessiveInvalidation();
        }
        nonceSequenceNumber[key] = targetSeq;
        emit NonceInvalidated(newNonce);
    }

    /// @inheritdoc INonceManager
    function getSeq(uint256 key) external view override returns (uint256 seq) {
        return nonceSequenceNumber[uint192(key)];
    }

    /// @notice Validates that the provided nonce is valid and increments the sequence number
    /// @param nonce A 256-bit value where:
    ///             - Upper 192 bits: the sequence key
    ///             - Lower 64 bits: must match the expected sequence number for the key
    /// @dev If valid, increments the sequence number for future nonce validations
    function _useNonce(uint256 nonce) internal {
        uint192 key = uint192(nonce >> 64);
        uint64 seq = uint64(nonce);
        if (!(nonceSequenceNumber[key]++ == seq)) {
            revert InvalidNonce();
        }
    }
}

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

import {Call, CallLib} from "./CallLib.sol";

struct BatchedCall {
    Call[] calls;
    bool revertOnFailure;
}

/// @title BatchedCallLib
/// @notice Library for EIP-712 hashing of BatchedCall
library BatchedCallLib {
    using CallLib for Call[];

    /// @dev The type string for the BatchedCall struct
    bytes internal constant BATCHED_CALL_TYPE =
        "BatchedCall(Call[] calls,bool revertOnFailure)Call(address to,uint256 value,bytes data)";
    /// @dev The typehash for the BatchedCall struct
    bytes32 internal constant BATCHED_CALL_TYPEHASH = keccak256(BATCHED_CALL_TYPE);

    function hash(BatchedCall memory batchedCall) internal pure returns (bytes32) {
        return keccak256(abi.encode(BATCHED_CALL_TYPEHASH, batchedCall.calls.hash(), batchedCall.revertOnFailure));
    }
}

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

struct Call {
    address to;
    uint256 value;
    bytes data;
}

/// @title CallLib
/// @notice A library for hashing and encoding calls
library CallLib {
    /// @dev The type string for the Call struct
    bytes internal constant CALL_TYPE = "Call(address to,uint256 value,bytes data)";

    /// @dev The typehash for the Call struct
    bytes32 internal constant CALL_TYPEHASH = keccak256(CALL_TYPE);

    /// @notice Hash a single struct according to EIP-712.
    function hash(Call memory call) internal pure returns (bytes32) {
        return keccak256(abi.encode(CALL_TYPEHASH, call.to, call.value, keccak256(call.data)));
    }

    /// @notice Hash an array of structs according to EIP-712.
    function hash(Call[] memory calls) internal pure returns (bytes32) {
        bytes32[] memory hashes = new bytes32[](calls.length);
        unchecked {
            for (uint256 i = 0; i < calls.length; i++) {
                hashes[i] = hash(calls[i]);
            }
        }
        return keccak256(abi.encodePacked(hashes));
    }
}

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

/// @title CalldataDecoder
library CalldataDecoder {
    /// @notice mask used for offsets and lengths to ensure no overflow
    /// @dev no sane abi encoding will pass in an offset or length greater than type(uint32).max
    ///      (note that this does deviate from standard solidity behavior and offsets/lengths will
    ///      be interpreted as mod type(uint32).max which will only impact malicious/buggy callers)
    uint256 constant OFFSET_OR_LENGTH_MASK = 0xffffffff;

    /// error SliceOutOfBounds();
    uint256 constant SLICE_ERROR_SELECTOR = 0x3b99b53d;

    /// @notice Removes the selector from the calldata and returns the encoded params.
    function removeSelector(bytes calldata data) internal pure returns (bytes calldata params) {
        assembly ("memory-safe") {
            if lt(data.length, 4) {
                mstore(0, SLICE_ERROR_SELECTOR)
                revert(0x1c, 4)
            }
            params.offset := add(data.offset, 4)
            params.length := sub(data.length, 4)
        }
    }

    /// @notice Decode the `_arg`-th element in `_bytes` as `bytes`
    /// @dev Performs a length check, returning empty bytes if it fails. This MUST be checked by the caller.
    // @param _bytes The input bytes string to extract a bytes string from
    // @param _arg The index of the argument to extract
    function toBytes(bytes calldata _bytes, uint256 _arg) internal pure returns (bytes calldata res) {
        uint256 length;
        assembly ("memory-safe") {
            // The offset of the `_arg`-th element is `32 * arg`, which stores the offset of the length pointer.
            // shl(5, x) is equivalent to mul(32, x)
            let lengthPtr :=
                add(_bytes.offset, and(calldataload(add(_bytes.offset, shl(5, _arg))), OFFSET_OR_LENGTH_MASK))
            // the number of bytes in the bytes string
            length := and(calldataload(lengthPtr), OFFSET_OR_LENGTH_MASK)
            // the offset where the bytes string begins
            let offset := add(lengthPtr, 0x20)
            // assign the return parameters
            res.length := length
            res.offset := offset

            // if the provided bytes string isnt as long as the encoding says, return empty bytes
            if lt(add(_bytes.length, _bytes.offset), add(length, offset)) {
                res.length := 0
                res.offset := 0
            }
        }
    }

    /// @notice Decode the `_arg`-th element in `_bytes` as `bytes`
    /// @dev Reverts if the length is not what the encoding is expecting
    // @param _bytes The input bytes string to extract a bytes string from
    // @param _arg The index of the argument to extract
    function safeToBytes(bytes calldata _bytes, uint256 _arg) internal pure returns (bytes calldata res) {
        uint256 length;
        assembly ("memory-safe") {
            // The offset of the `_arg`-th element is `32 * arg`, which stores the offset of the length pointer.
            // shl(5, x) is equivalent to mul(32, x)
            let lengthPtr :=
                add(_bytes.offset, and(calldataload(add(_bytes.offset, shl(5, _arg))), OFFSET_OR_LENGTH_MASK))
            // the number of bytes in the bytes string
            length := and(calldataload(lengthPtr), OFFSET_OR_LENGTH_MASK)
            // the offset where the bytes string begins
            let offset := add(lengthPtr, 0x20)
            // assign the return parameters
            res.length := length
            res.offset := offset

            // if the provided bytes string isnt as long as the encoding says, revert
            if lt(add(_bytes.length, _bytes.offset), add(length, offset)) {
                mstore(0, SLICE_ERROR_SELECTOR)
                revert(0x1c, 4)
            }
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.23;

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

/// @title ERC7739Utils
/// @author Extends the original implementation at
/// https://github.com/OpenZeppelin/openzeppelin-community-contracts/blob/53f590e4f4902bee0e06e455332e3321c697ea8b/contracts/utils/cryptography/ERC7739Utils.sol
library ERC7739Utils {
    /// @notice Hash a PersonalSign struct with the app's domain separator to produce an EIP-712 compatible hash
    /// @dev Uses this account's domain separator in the EIP-712 hash for replay protection
    /// @param hash The hashed message, calculated offchain
    /// @param domainSeparator This account's domain separator
    /// @return The PersonalSign nested EIP-712 hash of the message
    function toPersonalSignTypedDataHash(bytes32 hash, bytes32 domainSeparator) internal pure returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(domainSeparator, PersonalSignLib.hash(hash));
    }

    /// @notice Hash TypedDataSign with the app's domain separator to produce an EIP-712 compatible hash
    /// @dev Includes this account's domain in the hash for replay protection
    /// @param contentsHash The hash of the contents, per EIP-712
    /// @param domainBytes The encoded domain bytes from EIP-5267
    /// @param appSeparator The app's domain separator
    /// @param contentsName The type name of the contents
    /// @param contentsType The type description of the contents
    function toNestedTypedDataSignHash(
        bytes32 contentsHash,
        bytes memory domainBytes,
        bytes32 appSeparator,
        string calldata contentsName,
        string calldata contentsType
    ) internal pure returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(
            appSeparator, TypedDataSignLib.hash(contentsName, contentsType, contentsHash, domainBytes)
        );
    }

    /// @notice Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit modes
    /// @dev Returns empty strings if the contentsDescr is invalid, which must be handled by the calling function
    /// @return contentsName The type name of the contents
    /// @return contentsType The type description of the contents
    function decodeContentsDescr(string calldata contentsDescr)
        internal
        pure
        returns (string calldata contentsName, string calldata contentsType)
    {
        bytes calldata buffer = bytes(contentsDescr);
        if (buffer.length == 0) {
            // pass through (fail)
        } else if (buffer[buffer.length - 1] == bytes1(")")) {
            // Implicit mode: read contentsName from the beginning, and keep the complete descr
            for (uint256 i = 0; i < buffer.length; ++i) {
                bytes1 current = buffer[i];
                if (current == bytes1("(")) {
                    // if name is empty - passthrough (fail)
                    if (i == 0) break;
                    // we found the end of the contentsName
                    return (string(buffer[:i]), contentsDescr);
                } else if (_isForbiddenChar(current)) {
                    // we found an invalid character (forbidden) - passthrough (fail)
                    break;
                }
            }
        } else {
            // Explicit mode: read contentsName from the end, and remove it from the descr
            for (uint256 i = buffer.length; i > 0; --i) {
                bytes1 current = buffer[i - 1];
                if (current == bytes1(")")) {
                    // we found the end of the contentsName
                    return (string(buffer[i:]), string(buffer[:i]));
                } else if (_isForbiddenChar(current)) {
                    // we found an invalid character (forbidden) - passthrough (fail)
                    break;
                }
            }
        }
        // If we didn't find a valid contentsName, return empty strings
        assembly ("memory-safe") {
            contentsName.offset := 0
            contentsName.length := 0
            contentsType.offset := 0
            contentsType.length := 0
        }
    }

    /// @notice Perform onchain sanitization of contentsName as defined by the ERC-7739 spec
    /// @dev Following ERC-7739 specifications, a `contentsName` is considered invalid if it's empty or it contains
    /// any of the following bytes: ", )\x00"
    function _isForbiddenChar(bytes1 char) private pure returns (bool) {
        return char == 0x00 || char == bytes1(" ") || char == bytes1(",") || char == bytes1("(") || char == bytes1(")");
    }
}

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

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

/// @title HooksLib
/// @notice Hooks are invoked by inspecting the least significant bits of the address it is deployed to
/// For example, a hook deployed to address: 0x000000000000000000000000000000000000000a
/// has the lowest bits '1010' which would cause the `afterValidateUserOp`, and `beforeExecute` hooks to be used.
/// @author Inspired by https://github.com/Uniswap/v4-core/blob/main/src/libraries/Hooks.sol
library HooksLib {
    using HooksLib for IHook;

    /// @notice Internal constant hook flags
    uint160 internal constant AFTER_VERIFY_SIGNATURE_FLAG = 1 << 0;
    uint160 internal constant AFTER_VALIDATE_USER_OP_FLAG = 1 << 1;
    uint160 internal constant AFTER_IS_VALID_SIGNATURE_FLAG = 1 << 2;
    uint160 internal constant BEFORE_EXECUTE_FLAG = 1 << 3;
    uint160 internal constant AFTER_EXECUTE_FLAG = 1 << 4;

    /// @notice Hook did not return its selector
    error InvalidHookResponse();

    /// @notice Returns whether the flag is configured for the hook
    function hasPermission(IHook self, uint160 flag) internal pure returns (bool) {
        return uint160(address(self)) & flag != 0;
    }

    /// @notice Handles the afterValidateUserOp hook
    /// @notice MAY revert if desired according to ERC-4337 spec
    /// @dev Expected to validate the userOp and return a validationData which will override the internally computed validationData
    function handleAfterValidateUserOp(
        IHook self,
        bytes32 keyHash,
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 validationData,
        bytes memory hookData
    ) internal view {
        if (self.hasPermission(HooksLib.AFTER_VALIDATE_USER_OP_FLAG)) {
            (bytes4 hookSelector) = self.afterValidateUserOp(keyHash, userOp, userOpHash, validationData, hookData);
            if (hookSelector != IValidationHook.afterValidateUserOp.selector) revert InvalidHookResponse();
        }
    }

    /// @notice Handles the afterIsValidSignature hook
    /// @notice MUST revert if validation fails
    /// @dev Expected to validate the signature and return a value which will override the internally computed ERC-1271 magic value
    function handleAfterIsValidSignature(IHook self, bytes32 keyHash, bytes32 digest, bytes memory hookData)
        internal
        view
    {
        if (self.hasPermission(HooksLib.AFTER_IS_VALID_SIGNATURE_FLAG)) {
            bytes4 hookSelector = self.afterIsValidSignature(keyHash, digest, hookData);
            if (hookSelector != IValidationHook.afterIsValidSignature.selector) revert InvalidHookResponse();
        }
    }

    /// @notice Handles the afterVerifySignature hook
    /// @notice MUST revert if validation fails
    function handleAfterVerifySignature(IHook self, bytes32 keyHash, bytes32 digest, bytes memory hookData)
        internal
        view
    {
        if (self.hasPermission(HooksLib.AFTER_VERIFY_SIGNATURE_FLAG)) {
            bytes4 hookSelector = self.afterVerifySignature(keyHash, digest, hookData);
            if (hookSelector != IValidationHook.afterVerifySignature.selector) revert InvalidHookResponse();
        }
    }

    /// @notice Handles the beforeExecute hook
    /// @dev Expected to revert if the execution should be reverted
    /// @return beforeExecuteData any data which the hook wishes to be passed into the afterExecute hook
    function handleBeforeExecute(IHook self, bytes32 keyHash, address to, uint256 value, bytes memory data)
        internal
        returns (bytes memory beforeExecuteData)
    {
        if (self.hasPermission(HooksLib.BEFORE_EXECUTE_FLAG)) {
            bytes4 hookSelector;
            (hookSelector, beforeExecuteData) = self.beforeExecute(keyHash, to, value, data);
            if (hookSelector != IExecutionHook.beforeExecute.selector) revert InvalidHookResponse();
        }
    }

    /// @notice Handles the afterExecute hook
    /// @param beforeExecuteData data returned from the beforeExecute hook
    /// @dev Expected to revert if the execution should be reverted
    function handleAfterExecute(
        IHook self,
        bytes32 keyHash,
        bool success,
        bytes memory output,
        bytes memory beforeExecuteData
    ) internal {
        if (self.hasPermission(HooksLib.AFTER_EXECUTE_FLAG)) {
            bytes4 hookSelector = self.afterExecute(keyHash, success, output, beforeExecuteData);
            if (hookSelector != IExecutionHook.afterExecute.selector) revert InvalidHookResponse();
        }
    }
}

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

import {P256} from "@openzeppelin/contracts/utils/cryptography/P256.sol";
import {EfficientHashLib} from "solady/utils/EfficientHashLib.sol";
import {ECDSA} from "solady/utils/ECDSA.sol";
import {WebAuthn} from "webauthn-sol/src/WebAuthn.sol";

/// @dev The type of key.
enum KeyType {
    P256,
    WebAuthnP256,
    Secp256k1
}

struct Key {
    /// @dev Type of key. See the {KeyType} enum.
    KeyType keyType;
    /// @dev Public key in encoded form.
    bytes publicKey;
}

library KeyLib {
    /// @notice The sentinel hash value used to represent the root key

    bytes32 public constant ROOT_KEY_HASH = bytes32(0);

    /// @notice Hashes a key
    /// @dev uses the key type and the public key to produce a hash
    function hash(Key memory key) internal pure returns (bytes32) {
        return keccak256(abi.encode(key.keyType, keccak256(key.publicKey)));
    }

    /// @notice Returns whether the keyHash is the root key hash
    function isRootKey(bytes32 keyHash) internal pure returns (bool) {
        return keyHash == ROOT_KEY_HASH;
    }

    /// @notice Returns whether the key is the root key
    function isRootKey(Key memory key) internal view returns (bool) {
        return key.keyType == KeyType.Secp256k1 && abi.decode(key.publicKey, (address)) == address(this);
    }

    /// @notice A helper function to get the root key object.
    function toRootKey() internal view returns (Key memory) {
        return Key({keyType: KeyType.Secp256k1, publicKey: abi.encode(address(this))});
    }

    /// @notice Turns a calling address into a key hash.
    /// @dev This key must be a SECP256K1 key since it is calling the contract.
    function toKeyHash(address caller) internal view returns (bytes32) {
        if (caller == address(this)) return ROOT_KEY_HASH;
        return hash(Key({keyType: KeyType.Secp256k1, publicKey: abi.encode(caller)}));
    }

    /// @notice Verifies a signature from `key` over a `_hash`
    /// @dev Signatures from P256 are expected to be over the `sha256` hash of `_hash`
    function verify(Key memory key, bytes32 _hash, bytes calldata signature) internal view returns (bool isValid) {
        if (key.keyType == KeyType.Secp256k1) {
            address result = ECDSA.tryRecoverCalldata(_hash, signature);
            isValid = result == address(0) ? false : result == abi.decode(key.publicKey, (address));
        } else if (key.keyType == KeyType.P256) {
            // Extract x,y from the public key
            (bytes32 x, bytes32 y) = abi.decode(key.publicKey, (bytes32, bytes32));
            // Split signature into r and s values.
            (bytes32 r, bytes32 s) = abi.decode(signature, (bytes32, bytes32));
            isValid = P256.verify(EfficientHashLib.sha2(_hash), r, s, x, y);
        } else if (key.keyType == KeyType.WebAuthnP256) {
            // Extract x,y from the public key
            (uint256 x, uint256 y) = abi.decode(key.publicKey, (uint256, uint256));
            // Decode the signature into the WebAuthnAuth struct
            WebAuthn.WebAuthnAuth memory auth = abi.decode(signature, (WebAuthn.WebAuthnAuth));
            isValid = WebAuthn.verify({challenge: abi.encode(_hash), requireUV: false, webAuthnAuth: auth, x: x, y: y});
        } else {
            isValid = false;
        }
    }
}

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

using ModeDecoder for bytes32;

/// @title ModeDecoder
/// @notice Decodes a bytes32 mode as specified in ERC-7821 and ERC-7579.
/// @dev This library only supports two modes: BATCHED_CALL and BATCHED_CAN_REVERT_CALL.
library ModeDecoder {
    // Mode layout adhering to ERC-7579
    // 1 byte           | 1 byte    | 4 bytes       | 4 bytes       | 22 bytes
    // CALL_TYPE        | EXEC_TYPE | UNUSED        | MODE_SELECTOR | MODE_PAYLOAD
    bytes32 constant BATCHED_CALL = 0x0100000000000000000000000000000000000000000000000000000000000000;
    bytes32 constant BATCHED_CAN_REVERT_CALL = 0x0101000000000000000000000000000000000000000000000000000000000000;

    // Mode Masks
    bytes32 constant EXTRACT_EXEC_TYPE = 0x00ff000000000000000000000000000000000000000000000000000000000000;

    // Supported modes:
    // 0x01           | 0x00      | unused        | 0x00000000   | unused
    // 0x01           | 0x01      | unused        | 0x00000000   | unused
    // - A batched call that reverts on failure, specifying mode selector 0x00000000 means no other data is present
    // - A batched call that does not revert on failure, specifying mode selector 0x00000000 means no other data is present
    function isBatchedCall(bytes32 mode) internal pure returns (bool) {
        return mode == BATCHED_CALL || mode == BATCHED_CAN_REVERT_CALL;
    }

    // Revert if the EXEC_TYPE is 0.
    // The EXEC_TYPE is guaranteed to be ONLY 1 or 0 since the mode is checked with strict equality in isBatchedCall().
    function revertOnFailure(bytes32 mode) internal pure returns (bool) {
        return mode & EXTRACT_EXEC_TYPE == 0;
    }
}

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

import {IHook} from "../interfaces/IHook.sol";

type Settings is uint256;

/// @title SettingsLib
/// @notice Key settings are packed into a uint256 where
/// - the least significant 20 bytes (0-19) specify an address to callout to for extra or overrideable validation.
/// - bytes 20-24 are used for the expiration timestamp.
/// - byte 25 is used to specify if the key is an admin key or not.
/// - the remaining bytes are reserved for future use.
///   6 bytes |   1 byte       | 5 bytes           | 20 bytes
///   UNUSED  |   isAdmin      | expiration        | hook
library SettingsLib {
    uint160 constant MASK_20_BYTES = uint160(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
    uint40 constant MASK_5_BYTES = uint40(0xFFFFFFFFFF);
    uint8 constant MASK_1_BYTE = uint8(0xFF);

    Settings constant DEFAULT = Settings.wrap(0);
    // RootKey has the settings: (isAdmin = true, 0 expiration, no hook)
    Settings constant ROOT_KEY_SETTINGS = Settings.wrap(uint256(1) << 200);

    /// @notice Returns whether the key is an admin key
    function isAdmin(Settings settings) internal pure returns (bool _isAdmin) {
        uint8 mask = MASK_1_BYTE;
        assembly {
            _isAdmin := and(shr(200, settings), mask)
        }
    }

    /// @notice Returns the expiration timestamp in unix time
    function expiration(Settings settings) internal pure returns (uint40 _expiration) {
        uint40 mask = MASK_5_BYTES;
        assembly {
            _expiration := and(shr(160, settings), mask)
        }
    }

    /// @notice Returns the hook address of the key
    function hook(Settings settings) internal pure returns (IHook _hook) {
        uint256 mask = MASK_20_BYTES;
        assembly {
            _hook := and(settings, mask)
        }
    }

    /// @notice A key is expired if its expiration is less than the current block timestamp
    ///         Strictly less than is inline with how expiry is handled in the ERC-4337 EntryPoint contract
    /// @dev Keys with expiry of 0 never expire.
    function isExpired(Settings settings) internal view returns (bool _isExpired, uint40 _expiration) {
        uint40 _exp = expiration(settings);
        if (_exp == 0) return (false, 0);
        return (_exp < block.timestamp, _exp);
    }
}

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

import {BatchedCallLib, BatchedCall} from "./BatchedCallLib.sol";

struct SignedBatchedCall {
    BatchedCall batchedCall;
    uint256 nonce;
    bytes32 keyHash;
    address executor; // address(0) allows anyone to execute the batched call
    uint256 deadline; // a deadline of 0 never expires
}

/// @title SignedBatchedCallLib
/// @notice Library for EIP-712 hashing of SignedBatchedCall
library SignedBatchedCallLib {
    using BatchedCallLib for BatchedCall;

    /// @dev The type string for the SignedBatchedCall struct
    bytes internal constant SIGNED_BATCHED_CALL_TYPE =
        "SignedBatchedCall(BatchedCall batchedCall,uint256 nonce,bytes32 keyHash,address executor,uint256 deadline)BatchedCall(Call[] calls,bool revertOnFailure)Call(address to,uint256 value,bytes data)";
    /// @dev The typehash for the SignedBatchedCall struct
    bytes32 internal constant SIGNED_BATCHED_CALL_TYPEHASH = keccak256(SIGNED_BATCHED_CALL_TYPE);

    /// @notice Hashes a SignedBatchedCall struct.
    function hash(SignedBatchedCall memory signedBatchedCall) internal pure returns (bytes32) {
        return keccak256(
            abi.encode(
                SIGNED_BATCHED_CALL_TYPEHASH,
                signedBatchedCall.batchedCall.hash(),
                signedBatchedCall.nonce,
                signedBatchedCall.keyHash,
                signedBatchedCall.executor,
                signedBatchedCall.deadline
            )
        );
    }
}

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

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

/// @title WrappedSignatureLib
/// @notice A library for handling signatures with different wrapping schemes
library WrappedSignatureLib {
    using CalldataDecoder for bytes;

    /// error InvalidSignatureLength();
    uint256 constant INVALID_SIGNATURE_LENGTH_SELECTOR = 0x4be6321b;

    /// @notice Returns true if the signature is empty
    /// @dev For use in the ERC-7739 sentinel value check
    function isEmpty(bytes calldata data) internal pure returns (bool) {
        return data.length == 0;
    }

    /// @notice Returns true for standard or compact length ECDSA signatures
    /// @dev will also return true for standard p256 signatures however those MUST be wrapped with extra information in the verify sig flow
    function isRawSignature(bytes calldata data) internal pure returns (bool) {
        return data.length == 65 || data.length == 64;
    }

    /// @notice Decode the signature and hook data from the calldata
    /// @dev The calldata is expected to be encoded as `abi.encode(bytes signature, bytes hookData)`
    /// If the length of the data does not match the encoded length the function will revert with `SliceOutOfBounds()`
    /// Also, if the signature is less than 64 bytes, it will revert with `InvalidSignatureLength()`
    function decodeWithHookData(bytes calldata data)
        internal
        pure
        returns (bytes calldata signature, bytes calldata hookData)
    {
        signature = data.safeToBytes(0);
        hookData = data.safeToBytes(1);
        assembly ("memory-safe") {
            if lt(signature.length, 64) {
                mstore(0, INVALID_SIGNATURE_LENGTH_SELECTOR)
                revert(0x1c, 4)
            }
        }
    }

    /// @notice Decode the keyHash, signature, and hook data from the calldata
    /// @dev The calldata is expected to be encoded as `abi.encode(bytes32 keyHash, bytes signature, bytes hookData)`
    /// If the length of the data does not match the encoded length the function will revert with `SliceOutOfBounds()`
    /// Also, if the signature is less than 64 bytes, it will revert with `InvalidSignatureLength()`
    function decodeWithKeyHashAndHookData(bytes calldata data)
        internal
        pure
        returns (bytes32 keyHash, bytes calldata signature, bytes calldata hookData)
    {
        assembly {
            keyHash := calldataload(data.offset)
        }
        signature = data.safeToBytes(1);
        hookData = data.safeToBytes(2);
        assembly ("memory-safe") {
            if lt(signature.length, 64) {
                mstore(0, INVALID_SIGNATURE_LENGTH_SELECTOR)
                revert(0x1c, 4)
            }
        }
    }

    /// @notice Decode the signature, appSeparator, contentsHash, and contentsDescr from the calldata
    ///         the return values MUST be checked for length before use
    /// @dev The calldata is expected to be encoded as `abi.encode(bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr)`
    ///      there may be an uint16 contentsLength at the end of the calldata, but this is not used
    /// This function should NOT revert, and just returns empty values if the bytes length are incorrect.
    function decodeAsTypedDataSig(bytes calldata data)
        internal
        pure
        returns (bytes calldata signature, bytes32 appSeparator, bytes32 contentsHash, string calldata contentsDescr)
    {
        signature = data.toBytes(0);
        assembly {
            appSeparator := calldataload(add(data.offset, 0x20))
            contentsHash := calldataload(add(data.offset, 0x40))
        }
        contentsDescr = string(data.toBytes(3));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    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 success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        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 success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(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.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * 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²⁵⁶ and mod 2²⁵⁶ - 1, then use
            // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2²⁵⁶ + 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²⁵⁶. Also prevents denominator == 0.
            if (denominator <= prod1) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

            ///////////////////////////////////////////////
            // 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²⁵⁶ / 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²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            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⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // 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²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, 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;
        }
    }

    /**
     * @dev 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) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
        for (uint256 i = 0; i < byteArray.length; ++i) {
            if (byteArray[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @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;
        uint256 exp;
        unchecked {
            exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
            value >>= exp;
            result += exp;

            exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
            value >>= exp;
            result += exp;

            exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
            value >>= exp;
            result += exp;

            exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
            value >>= exp;
            result += exp;

            exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
            value >>= exp;
            result += exp;

            exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
            value >>= exp;
            result += exp;

            exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
            value >>= exp;
            result += exp;

            result += SafeCast.toUint(value > 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
        }
    }

    /**
     * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
        }
    }

    /**
     * @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;
        uint256 isGt;
        unchecked {
            isGt = SafeCast.toUint(value > (1 << 128) - 1);
            value >>= isGt * 128;
            result += isGt * 16;

            isGt = SafeCast.toUint(value > (1 << 64) - 1);
            value >>= isGt * 64;
            result += isGt * 8;

            isGt = SafeCast.toUint(value > (1 << 32) - 1);
            value >>= isGt * 32;
            result += isGt * 4;

            isGt = SafeCast.toUint(value > (1 << 16) - 1);
            value >>= isGt * 16;
            result += isGt * 2;

            result += SafeCast.toUint(value > (1 << 8) - 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
        }
    }

    /**
     * @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 34 of 63 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

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

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

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

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

/// @title IValidationHook
/// @notice Hook interface for optional signature validation logic
/// @dev The keyHash is validated against the signature before each hook is called, but
///      the hookData is NOT signed over or validated within the account. It MUST be treated as unsafe and can be set by anybody.
interface IValidationHook {
    /// @notice Hook called after `validateUserOp` is called on the account by the entrypoint
    /// @param keyHash the key which signed over userOpHash
    /// @param userOp UserOperation
    /// @param userOpHash hash of the UserOperation
    /// @param validationData contains data about whether or not the signature is valid and expiration information
    /// @param hookData any data to be passed to the hook. This has NOT been validated by the user signature
    /// @return selector Must be afterValidateUserOp.selector
    /// @dev The hook can revert to prevent the UserOperation from being validated.
    function afterValidateUserOp(
        bytes32 keyHash,
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 validationData,
        bytes calldata hookData
    ) external view returns (bytes4 selector);

    /// @notice Hook called after verifying a signature over a digest in an EIP-1271 callback.
    /// @dev MUST revert to signal that validation should fail
    /// @param keyHash the key which signed over digest
    /// @param digest the digest to verify
    /// @param hookData any data to be passed to the hook.This has NOT been validated by the user signature
    /// @return selector Must be afterIsValidSignature.selector
    function afterIsValidSignature(bytes32 keyHash, bytes32 digest, bytes calldata hookData)
        external
        view
        returns (bytes4 selector);

    /// @notice Hook called after verifying a signature over `SignedBatchedCall`.
    /// @dev MUST revert to signal that validation should fail
    /// @param keyHash the key which signed over digest
    /// @param digest the digest to verify
    /// @param hookData any data to be passed to the hook. This has NOT been validated by the user signature
    /// @return selector Must be afterVerifySignature.selector
    function afterVerifySignature(bytes32 keyHash, bytes32 digest, bytes calldata hookData)
        external
        view
        returns (bytes4 selector);
}

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

/// @title IExecutionHook
/// @notice Hooks that are executed before and after a Call is executed
interface IExecutionHook {
    /// @dev Must revert if the entire call should revert.
    /// @param keyHash The key hash to check against
    /// @param to The address to call
    /// @param value value of the call
    /// @return Context to pass to afterExecute hook, if present. An empty bytes array MAY be returned.
    function beforeExecute(bytes32 keyHash, address to, uint256 value, bytes calldata data)
        external
        returns (bytes4, bytes memory);

    /// @dev Must revert if the entire call should revert.
    /// @param keyHash The key hash to check against
    /// @param success Whether the call succeeded
    /// @param output The output of the call
    /// @param beforeExecuteData The context returned by the beforeExecute hook.
    function afterExecute(bytes32 keyHash, bool success, bytes calldata output, bytes calldata beforeExecuteData)
        external
        returns (bytes4);
}

File 37 of 63 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

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

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

/// @title IERC4337Account Interface
/// @notice Interface for contracts that support updating the EntryPoint contract
/// @dev Extends the IAccount interface from the ERC4337 specification
interface IERC4337Account is IAccount {
    /// Thrown when the caller to validateUserOp is not the EntryPoint contract
    error NotEntryPoint();

    /// @notice Emitted when the EntryPoint address is updated
    /// @param newEntryPoint The new EntryPoint address
    event EntryPointUpdated(address indexed newEntryPoint);

    /// @notice Updates the EntryPoint address
    /// @dev 4337 support is enabled by default, so this must be called with address(0) in order to disable it.
    /// @param entryPoint The new EntryPoint address
    function updateEntryPoint(address entryPoint) external;

    /// @notice Returns the address of the EntryPoint contract that this account uses
    /// @return The address of the EntryPoint contract
    function ENTRY_POINT() external view returns (address);
}

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

interface IERC7201 {
    /// @notice Returns the namespace and version of the contract
    function namespaceAndVersion() external view returns (string memory);
    /// @notice Returns the current custom storage root of the contract
    function CUSTOM_STORAGE_ROOT() external view returns (bytes32);
}

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

/// @title IERC7914
interface IERC7914 {
    /// @notice Thrown when the caller's allowance is exceeded when transferring
    error AllowanceExceeded();
    /// @notice Thrown when the sender is not the expected one
    error IncorrectSender();
    /// @notice Thrown when the transfer of native tokens fails
    error TransferNativeFailed();

    /// @notice Emitted when a transfer from native is made
    event TransferFromNative(address indexed from, address indexed to, uint256 value);
    /// @notice Emitted when a native approval is made
    event ApproveNative(address indexed owner, address indexed spender, uint256 value);
    /// @notice Emitted when a transfer from native transient is made
    event TransferFromNativeTransient(address indexed from, address indexed to, uint256 value);
    /// @notice Emitted when a transient native approval is made
    event ApproveNativeTransient(address indexed owner, address indexed spender, uint256 value);
    /// @notice Emitted when the native allowance of a spender is updated when a transfer happens
    event NativeAllowanceUpdated(address indexed spender, uint256 value);

    /// @notice Returns the allowance of a spender
    function nativeAllowance(address spender) external view returns (uint256);

    /// @notice Returns the transient allowance of a spender
    function transientNativeAllowance(address spender) external view returns (uint256);

    /// @notice Transfers native tokens from the caller to a recipient
    /// @dev Doesn't forward transferFrom requests - the specified `from` address must be address(this)
    function transferFromNative(address from, address recipient, uint256 amount) external returns (bool);

    /// @notice Approves a spender to transfer native tokens on behalf of the caller
    function approveNative(address spender, uint256 amount) external returns (bool);

    /// @notice Transfers native tokens from the caller to a recipient with transient storage
    /// @dev Doesn't forward transferFrom requests - the specified `from` address must be address(this)
    function transferFromNativeTransient(address from, address recipient, uint256 amount) external returns (bool);

    /// @notice Approves a spender to transfer native tokens on behalf of the caller with transient storage
    function approveNativeTransient(address spender, uint256 amount) external returns (bool);
}

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

/// @title IEIP712
interface IEIP712 {
    /// @notice Encode the EIP-5267 domain into bytes
    /// @dev for use in ERC-7739
    function domainBytes() external view returns (bytes memory);

    /// @notice Returns the `domainSeparator` used to create EIP-712 compliant hashes.
    /// @return The 32 bytes domain separator result.
    function domainSeparator() external view returns (bytes32);

    /// @notice Public getter for `_hashTypedData()` to produce a EIP-712 hash using this account's domain separator
    /// @param hash The nested typed data. Assumes the hash is the result of applying EIP-712 `hashStruct`.
    function hashTypedData(bytes32 hash) external view returns (bytes32);

    /// @notice Update the EIP-712 domain salt by setting the upper 96 bits to `prefix`
    ///   12 bytes | 20 bytes
    ///   prefix   | Implementation address (immutable, set on deployment)
    /// @dev Use this to invalidate existing signatures signed under the old domain separator
    /// @param prefix The prefix to set
    function updateSalt(uint96 prefix) external;
}

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

/// @title IMulticall
/// @notice Interface for the Multicall contract
interface IMulticall {
    /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
    /// @param data The encoded function data for each of the calls to make to this contract
    /// @return results The results from each of the calls passed in via data
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}

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

/// @title INonceManager
/// @notice Interface for managing nonces used to prevent replay attacks
/// @dev Each nonce consists of a 192-bit key and 64-bit sequence number
///      The key allows multiple independent nonce sequences
///      The sequence must be used in order (0, 1, 2, etc) for each key
interface INonceManager {
    /// @notice The event emitted when a nonce is invalidated
    event NonceInvalidated(uint256 nonce);

    /// @notice The error emitted when a nonce is invalid
    error InvalidNonce();

    /// @notice The error emitted when too many nonces are invalidated in one transaction
    error ExcessiveInvalidation();

    /// @notice Returns the next valid sequence number for a given key
    /// @param key The sequence key, passed as uint256 but only 192 bits are used.
    /// @return seq The sequence number padded to 256 bits but only the lower 64 bits should be used.
    function getSeq(uint256 key) external view returns (uint256 seq);

    /// @notice Invalidates all sequence numbers for a given key up to but not including the provided sequence number in the nonce
    /// @param newNonce The new nonce to set. Invalidates all sequence numbers for the key less than it.
    function invalidateNonce(uint256 newNonce) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an ERC-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) {
        assembly ("memory-safe") {
            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 ERC-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 ERC-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 (ERC-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) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

File 45 of 63 : BaseAuthorization.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

/// @title BaseAuthorization
/// @notice A base contract that provides a modifier to restrict access to the contract itself
contract BaseAuthorization {
    /// @notice An error that is thrown when an unauthorized address attempts to call a function
    error Unauthorized();

    /// @notice A modifier that restricts access to the contract itself
    modifier onlyThis() {
        if (msg.sender != address(this)) revert Unauthorized();
        _;
    }
}

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

/// @title PrefixedSaltLib
/// @notice A library for packing and updating the salt with a prefix for EIP-712 domain separators
library PrefixedSaltLib {
    /// @notice Pack the prefix and implementation address into a bytes32
    function pack(uint96 prefix, address implementation) internal pure returns (bytes32) {
        return bytes32((uint256(prefix) << 160) | uint160(implementation));
    }
}

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

/// @title EntrypointLib
/// @dev This library is used to dirty the most significant bit of the cached entrypoint
/// to indicate that the entrypoint has been overriden by the account
library EntrypointLib {
    uint256 internal constant ENTRY_POINT_OVERRIDDEN = 1 << 255;

    /// @notice Packs the entry point into a uint256.
    function pack(address entrypoint) internal pure returns (uint256) {
        return uint256(uint160(entrypoint)) | ENTRY_POINT_OVERRIDDEN;
    }

    /// @notice Unpacks the entry point address from a uint256.
    function unpack(uint256 packedEntrypoint) internal pure returns (address) {
        return address(uint160(packedEntrypoint & ~ENTRY_POINT_OVERRIDDEN));
    }

    /// @notice Checks if the entry point has been overriden by the user.
    function isOverriden(uint256 packedEntrypoint) internal pure returns (bool) {
        return packedEntrypoint & ENTRY_POINT_OVERRIDDEN != 0;
    }
}

File 48 of 63 : Static.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

/// @notice A library to store static values that are used across contracts
library Static {
    /// @notice The address of EntryPoint v0.8 deployed across all compatible chains
    address public constant ENTRY_POINT_V_0_8 = 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108;
}

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

/// @notice This is a temporary library that allows us to use transient storage (tstore/tload)
/// TODO: This library can be deleted when we have the transient keyword support in solidity.
/// @dev The custom storage layout keyword does not work for transient storage.
/// However, since transient storage is automatically cleared between transactions and does not persist, custom storage is not needed.
library TransientNativeAllowance {
    /// @notice calculates which storage slot a transient native allowance should be stored in for a given spender
    function _computeSlot(address spender) internal pure returns (bytes32 hashSlot) {
        assembly ("memory-safe") {
            mstore(0, and(spender, 0xffffffffffffffffffffffffffffffffffffffff))
            hashSlot := keccak256(0, 32)
        }
    }

    /// @notice Returns the transient allowance for a given spender
    function get(address spender) internal view returns (uint256 allowance) {
        bytes32 hashSlot = _computeSlot(spender);
        assembly ("memory-safe") {
            allowance := tload(hashSlot)
        }
    }

    /// @notice Sets the transient allowance for a given spender
    function set(address spender, uint256 allowance) internal {
        bytes32 hashSlot = _computeSlot(spender);
        assembly ("memory-safe") {
            tstore(hashSlot, allowance)
        }
    }
}

File 50 of 63 : PersonalSignLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

/// @title PersonalSignLib
/// @notice Library for hashing nested personal sign messages per ERC-7739
library PersonalSignLib {
    bytes private constant PERSONAL_SIGN_TYPE = "PersonalSign(bytes prefixed)";
    bytes32 private constant PERSONAL_SIGN_TYPEHASH = keccak256(PERSONAL_SIGN_TYPE);

    /// @notice Calculate the hash of the PersonalSign type according to EIP-712
    /// @dev This function is used within the context of ERC-1271 where we only have access to a bytes32 hash.
    ///      We assume that `message` is the hash of `prefixed`,
    /// keccak256("\x19Ethereum Signed Message:\n" || len(someMessage) || someMessage)
    ///      such that it is compatible with how EIP-712 handles dynamic types
    /// i.e. keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, keccak256(prefixed)))
    function hash(bytes32 message) internal pure returns (bytes32) {
        return keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, message));
    }
}

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

/// @title TypedDataSignLib
/// @notice Library supporting nesting of EIP-712 typed data signatures
/// Follows ERC-7739 spec
library TypedDataSignLib {
    /// @dev Generate the dynamic type string for the TypedDataSign struct
    /// @notice contentsName and contentsType MUST be checked for length before hashing
    function _toTypedDataSignTypeString(string memory contentsName, string memory contentsType)
        internal
        pure
        returns (bytes memory)
    {
        return abi.encodePacked(
            "TypedDataSign(",
            contentsName,
            " contents,string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)",
            contentsType
        );
    }

    /// @dev Create the type hash for a TypedDataSign struct
    /// @notice contentsName and contentsType MUST be checked for length before hashing
    function _toTypedDataSignTypeHash(string memory contentsName, string memory contentsType)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(_toTypedDataSignTypeString(contentsName, contentsType));
    }

    /// @notice EIP-712 hashStruct implementation for TypedDataSign
    /// @dev domainBytes is abi.encode(keccak256(bytes(name)), keccak256(bytes(version)), chainId, verifyingContract, salt)
    function hash(
        string memory contentsName,
        string memory contentsType,
        bytes32 contentsHash,
        bytes memory domainBytes
    ) internal pure returns (bytes32) {
        return keccak256(
            // Every element in domainBytes is statically sized, so we can do encodePacked here
            abi.encodePacked(_toTypedDataSignTypeHash(contentsName, contentsType), contentsHash, domainBytes)
        );
    }
}

File 52 of 63 : EfficientHashLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               MALLOC-LESS HASHING OPERATIONS               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(bytes32 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(uint256 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12,
        bytes32 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12,
        uint256 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

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

    /// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
    function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
        }
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, bytes32 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, uint256 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
    function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
        /// @solidity memory-safe-assembly
        assembly {
            buffer := mload(0x40)
            mstore(buffer, n)
            mstore(0x40, add(shl(5, add(1, n)), buffer))
        }
    }

    /// @dev Frees memory that has been allocated for `buffer`.
    /// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
    function free(bytes32[] memory buffer) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(buffer)
            mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      EQUALITY CHECKS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `a == abi.decode(b, (bytes32))`.
    function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
        }
    }

    /// @dev Returns `abi.decode(a, (bytes32)) == a`.
    function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
        }
    }

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

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hash(bytes memory b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hash(bytes memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(b, 0x20), mload(b))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hashCalldata(bytes calldata b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := keccak256(mload(0x40), b.length)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      SHA2-256 HELPERS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
    function sha2(bytes32 b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, b)
            result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2(bytes memory b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(end, start), sub(end, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(n, start), sub(n, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2(bytes memory b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import {FCL_ecdsa} from "FreshCryptoLib/FCL_ecdsa.sol";
import {FCL_Elliptic_ZZ} from "FreshCryptoLib/FCL_elliptic.sol";
import {Base64} from "openzeppelin-contracts/contracts/utils/Base64.sol";
import {LibString} from "solady/utils/LibString.sol";

/// @title WebAuthn
///
/// @notice A library for verifying WebAuthn Authentication Assertions, built off the work
///         of Daimo.
///
/// @dev Attempts to use the RIP-7212 precompile for signature verification.
///      If precompile verification fails, it falls back to FreshCryptoLib.
///
/// @author Coinbase (https://github.com/base-org/webauthn-sol)
/// @author Daimo (https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol)
library WebAuthn {
    using LibString for string;

    struct WebAuthnAuth {
        /// @dev The WebAuthn authenticator data.
        ///      See https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata.
        bytes authenticatorData;
        /// @dev The WebAuthn client data JSON.
        ///      See https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
        string clientDataJSON;
        /// @dev The index at which "challenge":"..." occurs in `clientDataJSON`.
        uint256 challengeIndex;
        /// @dev The index at which "type":"..." occurs in `clientDataJSON`.
        uint256 typeIndex;
        /// @dev The r value of secp256r1 signature
        uint256 r;
        /// @dev The s value of secp256r1 signature
        uint256 s;
    }

    /// @dev Bit 0 of the authenticator data struct, corresponding to the "User Present" bit.
    ///      See https://www.w3.org/TR/webauthn-2/#flags.
    bytes1 private constant _AUTH_DATA_FLAGS_UP = 0x01;

    /// @dev Bit 2 of the authenticator data struct, corresponding to the "User Verified" bit.
    ///      See https://www.w3.org/TR/webauthn-2/#flags.
    bytes1 private constant _AUTH_DATA_FLAGS_UV = 0x04;

    /// @dev Secp256r1 curve order / 2 used as guard to prevent signature malleability issue.
    uint256 private constant _P256_N_DIV_2 = FCL_Elliptic_ZZ.n / 2;

    /// @dev The precompiled contract address to use for signature verification in the “secp256r1” elliptic curve.
    ///      See https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md.
    address private constant _VERIFIER = address(0x100);

    /// @dev The expected type (hash) in the client data JSON when verifying assertion signatures.
    ///      See https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-type
    bytes32 private constant _EXPECTED_TYPE_HASH = keccak256('"type":"webauthn.get"');

    ///
    /// @notice Verifies a Webauthn Authentication Assertion as described
    /// in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion.
    ///
    /// @dev We do not verify all the steps as described in the specification, only ones relevant to our context.
    ///      Please carefully read through this list before usage.
    ///
    ///      Specifically, we do verify the following:
    ///         - Verify that authenticatorData (which comes from the authenticator, such as iCloud Keychain) indicates
    ///           a well-formed assertion with the user present bit set. If `requireUV` is set, checks that the authenticator
    ///           enforced user verification. User verification should be required if, and only if, options.userVerification
    ///           is set to required in the request.
    ///         - Verifies that the client JSON is of type "webauthn.get", i.e. the client was responding to a request to
    ///           assert authentication.
    ///         - Verifies that the client JSON contains the requested challenge.
    ///         - Verifies that (r, s) constitute a valid signature over both the authenicatorData and client JSON, for public
    ///            key (x, y).
    ///
    ///      We make some assumptions about the particular use case of this verifier, so we do NOT verify the following:
    ///         - Does NOT verify that the origin in the `clientDataJSON` matches the Relying Party's origin: tt is considered
    ///           the authenticator's responsibility to ensure that the user is interacting with the correct RP. This is
    ///           enforced by most high quality authenticators properly, particularly the iCloud Keychain and Google Password
    ///           Manager were tested.
    ///         - Does NOT verify That `topOrigin` in `clientDataJSON` is well-formed: We assume it would never be present, i.e.
    ///           the credentials are never used in a cross-origin/iframe context. The website/app set up should disallow
    ///           cross-origin usage of the credentials. This is the default behaviour for created credentials in common settings.
    ///         - Does NOT verify that the `rpIdHash` in `authenticatorData` is the SHA-256 hash of the RP ID expected by the Relying
    ///           Party: this means that we rely on the authenticator to properly enforce credentials to be used only by the correct RP.
    ///           This is generally enforced with features like Apple App Site Association and Google Asset Links. To protect from
    ///           edge cases in which a previously-linked RP ID is removed from the authorised RP IDs, we recommend that messages
    ///           signed by the authenticator include some expiry mechanism.
    ///         - Does NOT verify the credential backup state: this assumes the credential backup state is NOT used as part of Relying
    ///           Party business logic or policy.
    ///         - Does NOT verify the values of the client extension outputs: this assumes that the Relying Party does not use client
    ///           extension outputs.
    ///         - Does NOT verify the signature counter: signature counters are intended to enable risk scoring for the Relying Party.
    ///           This assumes risk scoring is not used as part of Relying Party business logic or policy.
    ///         - Does NOT verify the attestation object: this assumes that response.attestationObject is NOT present in the response,
    ///           i.e. the RP does not intend to verify an attestation.
    ///
    /// @param challenge    The challenge that was provided by the relying party.
    /// @param requireUV    A boolean indicating whether user verification is required.
    /// @param webAuthnAuth The `WebAuthnAuth` struct.
    /// @param x            The x coordinate of the public key.
    /// @param y            The y coordinate of the public key.
    ///
    /// @return `true` if the authentication assertion passed validation, else `false`.
    function verify(bytes memory challenge, bool requireUV, WebAuthnAuth memory webAuthnAuth, uint256 x, uint256 y)
        internal
        view
        returns (bool)
    {
        if (webAuthnAuth.s > _P256_N_DIV_2) {
            // guard against signature malleability
            return false;
        }

        // 11. Verify that the value of C.type is the string webauthn.get.
        //     bytes("type":"webauthn.get").length = 21
        string memory _type = webAuthnAuth.clientDataJSON.slice(webAuthnAuth.typeIndex, webAuthnAuth.typeIndex + 21);
        if (keccak256(bytes(_type)) != _EXPECTED_TYPE_HASH) {
            return false;
        }

        // 12. Verify that the value of C.challenge equals the base64url encoding of options.challenge.
        bytes memory expectedChallenge = bytes(string.concat('"challenge":"', Base64.encodeURL(challenge), '"'));
        string memory actualChallenge =
            webAuthnAuth.clientDataJSON.slice(webAuthnAuth.challengeIndex, webAuthnAuth.challengeIndex + expectedChallenge.length);
        if (keccak256(bytes(actualChallenge)) != keccak256(expectedChallenge)) {
            return false;
        }

        // Skip 13., 14., 15.

        // 16. Verify that the UP bit of the flags in authData is set.
        if (webAuthnAuth.authenticatorData[32] & _AUTH_DATA_FLAGS_UP != _AUTH_DATA_FLAGS_UP) {
            return false;
        }

        // 17. If user verification is required for this assertion, verify that the User Verified bit of the flags in
        //     authData is set.
        if (requireUV && (webAuthnAuth.authenticatorData[32] & _AUTH_DATA_FLAGS_UV) != _AUTH_DATA_FLAGS_UV) {
            return false;
        }

        // skip 18.

        // 19. Let hash be the result of computing a hash over the cData using SHA-256.
        bytes32 clientDataJSONHash = sha256(bytes(webAuthnAuth.clientDataJSON));

        // 20. Using credentialPublicKey, verify that sig is a valid signature over the binary concatenation of authData
        //     and hash.
        bytes32 messageHash = sha256(abi.encodePacked(webAuthnAuth.authenticatorData, clientDataJSONHash));
        bytes memory args = abi.encode(messageHash, webAuthnAuth.r, webAuthnAuth.s, x, y);
        // try the RIP-7212 precompile address
        (bool success, bytes memory ret) = _VERIFIER.staticcall(args);
        // staticcall will not revert if address has no code
        // check return length
        // note that even if precompile exists, ret.length is 0 when verification returns false
        // so an invalid signature will be checked twice: once by the precompile and once by FCL.
        // Ideally this signature failure is simulated offchain and no one actually pay this gas.
        bool valid = ret.length > 0;
        if (success && valid) return abi.decode(ret, (uint256)) == 1;

        return FCL_ecdsa.ecdsa_verify(messageHash, webAuthnAuth.r, webAuthnAuth.s, x, y);
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}

File 56 of 63 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

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

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    using SafeCast for *;

    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 The string being parsed contains characters that are not in scope of the given base.
     */
    error StringsInvalidChar();

    /**
     * @dev The string being parsed is not a properly formatted address.
     */
    error StringsInvalidAddressFormat();

    /**
     * @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;
            assembly ("memory-safe") {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                assembly ("memory-safe") {
                    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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
     * representation, according to EIP-55.
     */
    function toChecksumHexString(address addr) internal pure returns (string memory) {
        bytes memory buffer = bytes(toHexString(addr));

        // hash the hex part of buffer (skip length + 2 bytes, length 40)
        uint256 hashValue;
        assembly ("memory-safe") {
            hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
        }

        for (uint256 i = 41; i > 1; --i) {
            // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
            if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
                // case shift by xoring with 0x20
                buffer[i] ^= 0x20;
            }
            hashValue >>= 4;
        }
        return string(buffer);
    }

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

    /**
     * @dev Parse a decimal string and returns the value as a `uint256`.
     *
     * Requirements:
     * - The string must be formatted as `[0-9]*`
     * - The result must fit into an `uint256` type
     */
    function parseUint(string memory input) internal pure returns (uint256) {
        return parseUint(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `[0-9]*`
     * - The result must fit into an `uint256` type
     */
    function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
        (bool success, uint256 value) = tryParseUint(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
        return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
     * character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseUint(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, uint256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseUintUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseUintUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, uint256 value) {
        bytes memory buffer = bytes(input);

        uint256 result = 0;
        for (uint256 i = begin; i < end; ++i) {
            uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
            if (chr > 9) return (false, 0);
            result *= 10;
            result += chr;
        }
        return (true, result);
    }

    /**
     * @dev Parse a decimal string and returns the value as a `int256`.
     *
     * Requirements:
     * - The string must be formatted as `[-+]?[0-9]*`
     * - The result must fit in an `int256` type.
     */
    function parseInt(string memory input) internal pure returns (int256) {
        return parseInt(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `[-+]?[0-9]*`
     * - The result must fit in an `int256` type.
     */
    function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
        (bool success, int256 value) = tryParseInt(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
     * the result does not fit in a `int256`.
     *
     * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
     */
    function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
        return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
    }

    uint256 private constant ABS_MIN_INT256 = 2 ** 255;

    /**
     * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
     * character or if the result does not fit in a `int256`.
     *
     * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
     */
    function tryParseInt(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, int256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseIntUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseInt} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseIntUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, int256 value) {
        bytes memory buffer = bytes(input);

        // Check presence of a negative sign.
        bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        bool positiveSign = sign == bytes1("+");
        bool negativeSign = sign == bytes1("-");
        uint256 offset = (positiveSign || negativeSign).toUint();

        (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);

        if (absSuccess && absValue < ABS_MIN_INT256) {
            return (true, negativeSign ? -int256(absValue) : int256(absValue));
        } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
            return (true, type(int256).min);
        } else return (false, 0);
    }

    /**
     * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
     *
     * Requirements:
     * - The string must be formatted as `(0x)?[0-9a-fA-F]*`
     * - The result must fit in an `uint256` type.
     */
    function parseHexUint(string memory input) internal pure returns (uint256) {
        return parseHexUint(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseHexUint} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
     * - The result must fit in an `uint256` type.
     */
    function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
        (bool success, uint256 value) = tryParseHexUint(input, begin, end);
        if (!success) revert StringsInvalidChar();
        return value;
    }

    /**
     * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
        return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
     * invalid character.
     *
     * NOTE: This function will revert if the result does not fit in a `uint256`.
     */
    function tryParseHexUint(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, uint256 value) {
        if (end > bytes(input).length || begin > end) return (false, 0);
        return _tryParseHexUintUncheckedBounds(input, begin, end);
    }

    /**
     * @dev Implementation of {tryParseHexUint} that does not check bounds. Caller should make sure that
     * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
     */
    function _tryParseHexUintUncheckedBounds(
        string memory input,
        uint256 begin,
        uint256 end
    ) private pure returns (bool success, uint256 value) {
        bytes memory buffer = bytes(input);

        // skip 0x prefix if present
        bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        uint256 offset = hasPrefix.toUint() * 2;

        uint256 result = 0;
        for (uint256 i = begin + offset; i < end; ++i) {
            uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
            if (chr > 15) return (false, 0);
            result *= 16;
            unchecked {
                // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
                // This guaratees that adding a value < 16 will not cause an overflow, hence the unchecked.
                result += chr;
            }
        }
        return (true, result);
    }

    /**
     * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
     *
     * Requirements:
     * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
     */
    function parseAddress(string memory input) internal pure returns (address) {
        return parseAddress(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseAddress} that parses a substring of `input` located between position `begin` (included) and
     * `end` (excluded).
     *
     * Requirements:
     * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
     */
    function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
        (bool success, address value) = tryParseAddress(input, begin, end);
        if (!success) revert StringsInvalidAddressFormat();
        return value;
    }

    /**
     * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
     * formatted address. See {parseAddress} requirements.
     */
    function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
        return tryParseAddress(input, 0, bytes(input).length);
    }

    /**
     * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
     * formatted address. See {parseAddress} requirements.
     */
    function tryParseAddress(
        string memory input,
        uint256 begin,
        uint256 end
    ) internal pure returns (bool success, address value) {
        if (end > bytes(input).length || begin > end) return (false, address(0));

        bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
        uint256 expectedLength = 40 + hasPrefix.toUint() * 2;

        // check that input is the correct length
        if (end - begin == expectedLength) {
            // length guarantees that this does not overflow, and value is at most type(uint160).max
            (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
            return (s, address(uint160(v)));
        } else {
            return (false, address(0));
        }
    }

    function _tryParseChr(bytes1 chr) private pure returns (uint8) {
        uint8 value = uint8(chr);

        // Try to parse `chr`:
        // - Case 1: [0-9]
        // - Case 2: [a-f]
        // - Case 3: [A-F]
        // - otherwise not supported
        unchecked {
            if (value > 47 && value < 58) value -= 48;
            else if (value > 96 && value < 103) value -= 87;
            else if (value > 64 && value < 71) value -= 55;
            else return type(uint8).max;
        }

        return value;
    }

    /**
     * @dev Reads a bytes32 from a bytes array without bounds checking.
     *
     * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
     * assembly block as such would prevent some optimizations.
     */
    function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
        // This is not memory safe in the general case, but all calls to this private function are within bounds.
        assembly ("memory-safe") {
            value := mload(add(buffer, add(0x20, offset)))
        }
    }
}

//********************************************************************************************/
//  ___           _       ___               _         _    _ _
// | __| _ ___ __| |_    / __|_ _ _  _ _ __| |_ ___  | |  (_) |__
// | _| '_/ -_|_-< ' \  | (__| '_| || | '_ \  _/ _ \ | |__| | '_ \
// |_||_| \___/__/_||_|  \___|_|  \_, | .__/\__\___/ |____|_|_.__/
//                                |__/|_|
///* Copyright (C) 2022 - Renaud Dubois - This file is part of FCL (Fresh CryptoLib) project
///* License: This software is licensed under MIT License
///* This Code may be reused including license and copyright notice.
///* See LICENSE file at the root folder of the project.
///* FILE: FCL_ecdsa.sol
///*
///*
///* DESCRIPTION: ecdsa verification implementation
///*
//**************************************************************************************/
//* WARNING: this code SHALL not be used for non prime order curves for security reasons.
// Code is optimized for a=-3 only curves with prime order, constant like -1, -2 shall be replaced
// if ever used for other curve than sec256R1
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;


import {FCL_Elliptic_ZZ} from "./FCL_elliptic.sol";



library FCL_ecdsa {
    // Set parameters for curve sec256r1.public
      //curve order (number of points)
    uint256 constant n = FCL_Elliptic_ZZ.n;
  
    /**
     * @dev ECDSA verification, given , signature, and public key.
     */

    /**
     * @dev ECDSA verification, given , signature, and public key, no calldata version
     */
    function ecdsa_verify(bytes32 message, uint256 r, uint256 s, uint256 Qx, uint256 Qy)  internal view returns (bool){

        if (r == 0 || r >= FCL_Elliptic_ZZ.n || s == 0 || s >= FCL_Elliptic_ZZ.n) {
            return false;
        }
        
        if (!FCL_Elliptic_ZZ.ecAff_isOnCurve(Qx, Qy)) {
            return false;
        }

        uint256 sInv = FCL_Elliptic_ZZ.FCL_nModInv(s);

        uint256 scalar_u = mulmod(uint256(message), sInv, FCL_Elliptic_ZZ.n);
        uint256 scalar_v = mulmod(r, sInv, FCL_Elliptic_ZZ.n);
        uint256 x1;

        x1 = FCL_Elliptic_ZZ.ecZZ_mulmuladd_S_asm(Qx, Qy, scalar_u, scalar_v);

        x1= addmod(x1, n-r,n );
    
        return x1 == 0;
    }

    function ec_recover_r1(uint256 h, uint256 v, uint256 r, uint256 s) internal view returns (address)
    {
         if (r == 0 || r >= FCL_Elliptic_ZZ.n || s == 0 || s >= FCL_Elliptic_ZZ.n) {
            return address(0);
        }
        uint256 y=FCL_Elliptic_ZZ.ec_Decompress(r, v-27);
        uint256 rinv=FCL_Elliptic_ZZ.FCL_nModInv(r);
        uint256 u1=mulmod(FCL_Elliptic_ZZ.n-addmod(0,h,FCL_Elliptic_ZZ.n), rinv,FCL_Elliptic_ZZ.n);//-hr^-1
        uint256 u2=mulmod(s, rinv,FCL_Elliptic_ZZ.n);//sr^-1

        uint256 Qx;
        uint256 Qy;
        (Qx,Qy)=FCL_Elliptic_ZZ.ecZZ_mulmuladd(r,y, u1, u2);

        return address(uint160(uint256(keccak256(abi.encodePacked(Qx, Qy)))));
    }

    function ecdsa_precomputed_verify(bytes32 message, uint256 r, uint256 s, address Shamir8)
        internal view
        returns (bool)
    {
       
        if (r == 0 || r >= n || s == 0 || s >= n) {
            return false;
        }
        /* Q is pushed via the contract at address Shamir8 assumed to be correct
        if (!isOnCurve(Q[0], Q[1])) {
            return false;
        }*/

        uint256 sInv = FCL_Elliptic_ZZ.FCL_nModInv(s);

        uint256 X;

        //Shamir 8 dimensions
        X = FCL_Elliptic_ZZ.ecZZ_mulmuladd_S8_extcode(mulmod(uint256(message), sInv, n), mulmod(r, sInv, n), Shamir8);

        X= addmod(X, n-r,n );

        return X == 0;
    } //end  ecdsa_precomputed_verify()

     function ecdsa_precomputed_verify(bytes32 message, uint256[2] calldata rs, address Shamir8)
        internal view
        returns (bool)
    {
        uint256 r = rs[0];
        uint256 s = rs[1];
        if (r == 0 || r >= n || s == 0 || s >= n) {
            return false;
        }
        /* Q is pushed via the contract at address Shamir8 assumed to be correct
        if (!isOnCurve(Q[0], Q[1])) {
            return false;
        }*/

        uint256 sInv = FCL_Elliptic_ZZ.FCL_nModInv(s);

        uint256 X;

        //Shamir 8 dimensions
        X = FCL_Elliptic_ZZ.ecZZ_mulmuladd_S8_extcode(mulmod(uint256(message), sInv, n), mulmod(r, sInv, n), Shamir8);

        X= addmod(X, n-r,n );

        return X == 0;
    } //end  ecdsa_precomputed_verify()

}

//********************************************************************************************/
//  ___           _       ___               _         _    _ _
// | __| _ ___ __| |_    / __|_ _ _  _ _ __| |_ ___  | |  (_) |__
// | _| '_/ -_|_-< ' \  | (__| '_| || | '_ \  _/ _ \ | |__| | '_ \
// |_||_| \___/__/_||_|  \___|_|  \_, | .__/\__\___/ |____|_|_.__/
//                                |__/|_|
///* Copyright (C) 2022 - Renaud Dubois - This file is part of FCL (Fresh CryptoLib) project
///* License: This software is licensed under MIT License
///* This Code may be reused including license and copyright notice.
///* See LICENSE file at the root folder of the project.
///* FILE: FCL_elliptic.sol
///*
///*
///* DESCRIPTION: modified XYZZ system coordinates for EVM elliptic point multiplication
///*  optimization
///*
//**************************************************************************************/
//* WARNING: this code SHALL not be used for non prime order curves for security reasons.
// Code is optimized for a=-3 only curves with prime order, constant like -1, -2 shall be replaced
// if ever used for other curve than sec256R1
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

library FCL_Elliptic_ZZ {
    // Set parameters for curve sec256r1.

    // address of the ModExp precompiled contract (Arbitrary-precision exponentiation under modulo)
    address constant MODEXP_PRECOMPILE = 0x0000000000000000000000000000000000000005;
    //curve prime field modulus
    uint256 constant p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
    //short weierstrass first coefficient
    uint256 constant a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC;
    //short weierstrass second coefficient
    uint256 constant b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;
    //generating point affine coordinates
    uint256 constant gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;
    uint256 constant gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;
    //curve order (number of points)
    uint256 constant n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
    /* -2 mod p constant, used to speed up inversion and doubling (avoid negation)*/
    uint256 constant minus_2 = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFD;
    /* -2 mod n constant, used to speed up inversion*/
    uint256 constant minus_2modn = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F;

    uint256 constant minus_1 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
    //P+1 div 4
    uint256 constant pp1div4=0x3fffffffc0000000400000000000000000000000400000000000000000000000;
    //arbitrary constant to express no quadratic residuosity
    uint256 constant _NOTSQUARE=0xFFFFFFFF00000002000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
    uint256 constant _NOTONCURVE=0xFFFFFFFF00000003000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;

    /**
     * /* inversion mod n via a^(n-2), use of precompiled using little Fermat theorem
     */
    function FCL_nModInv(uint256 u) internal view returns (uint256 result) {
        assembly {
            let pointer := mload(0x40)
            // Define length of base, exponent and modulus. 0x20 == 32 bytes
            mstore(pointer, 0x20)
            mstore(add(pointer, 0x20), 0x20)
            mstore(add(pointer, 0x40), 0x20)
            // Define variables base, exponent and modulus
            mstore(add(pointer, 0x60), u)
            mstore(add(pointer, 0x80), minus_2modn)
            mstore(add(pointer, 0xa0), n)

            // Call the precompiled contract 0x05 = ModExp
            if iszero(staticcall(not(0), 0x05, pointer, 0xc0, pointer, 0x20)) { revert(0, 0) }
            result := mload(pointer)
        }
    }
    /**
     * /* @dev inversion mod nusing little Fermat theorem via a^(n-2), use of precompiled
     */

    function FCL_pModInv(uint256 u) internal view returns (uint256 result) {
        assembly {
            let pointer := mload(0x40)
            // Define length of base, exponent and modulus. 0x20 == 32 bytes
            mstore(pointer, 0x20)
            mstore(add(pointer, 0x20), 0x20)
            mstore(add(pointer, 0x40), 0x20)
            // Define variables base, exponent and modulus
            mstore(add(pointer, 0x60), u)
            mstore(add(pointer, 0x80), minus_2)
            mstore(add(pointer, 0xa0), p)

            // Call the precompiled contract 0x05 = ModExp
            if iszero(staticcall(not(0), 0x05, pointer, 0xc0, pointer, 0x20)) { revert(0, 0) }
            result := mload(pointer)
        }
    }

    //Coron projective shuffling, take as input alpha as blinding factor
   function ecZZ_Coronize(uint256 alpha, uint256 x, uint256 y,  uint256 zz, uint256 zzz) internal pure  returns (uint256 x3, uint256 y3, uint256 zz3, uint256 zzz3)
   {
       
        uint256 alpha2=mulmod(alpha,alpha,p);
       
        x3=mulmod(alpha2, x,p); //alpha^-2.x
        y3=mulmod(mulmod(alpha, alpha2,p), y,p);

        zz3=mulmod(zz,alpha2,p);//alpha^2 zz
        zzz3=mulmod(zzz,mulmod(alpha, alpha2,p),p);//alpha^3 zzz
        
        return (x3, y3, zz3, zzz3);
   }


 function ecZZ_Add(uint256 x1, uint256 y1, uint256 zz1, uint256 zzz1, uint256 x2, uint256 y2, uint256 zz2, uint256 zzz2) internal pure  returns (uint256 x3, uint256 y3, uint256 zz3, uint256 zzz3)
  {
    uint256 u1=mulmod(x1,zz2,p); // U1 = X1*ZZ2
    uint256 u2=mulmod(x2, zz1,p);               //  U2 = X2*ZZ1
    u2=addmod(u2, p-u1, p);//  P = U2-U1
    x1=mulmod(u2, u2, p);//PP
    x2=mulmod(x1, u2, p);//PPP
    
    zz3=mulmod(x1, mulmod(zz1, zz2, p),p);//ZZ3 = ZZ1*ZZ2*PP  
    zzz3=mulmod(zzz1, mulmod(zzz2, x2, p),p);//ZZZ3 = ZZZ1*ZZZ2*PPP

    zz1=mulmod(y1, zzz2,p);  // S1 = Y1*ZZZ2
    zz2=mulmod(y2, zzz1, p);    // S2 = Y2*ZZZ1 
    zz2=addmod(zz2, p-zz1, p);//R = S2-S1
    zzz1=mulmod(u1, x1,p); //Q = U1*PP
    x3= addmod(addmod(mulmod(zz2, zz2, p), p-x2,p), mulmod(minus_2, zzz1,p),p); //X3 = R2-PPP-2*Q
    y3=addmod( mulmod(zz2, addmod(zzz1, p-x3, p),p), p-mulmod(zz1, x2, p),p);//R*(Q-X3)-S1*PPP

    return (x3, y3, zz3, zzz3);
  }

/// @notice Calculate one modular square root of a given integer. Assume that p=3 mod 4.
/// @dev Uses the ModExp precompiled contract at address 0x05 for fast computation using little Fermat theorem
/// @param self The integer of which to find the modular inverse
/// @return result The modular inverse of the input integer. If the modular inverse doesn't exist, it revert the tx

function SqrtMod(uint256 self) internal view returns (uint256 result){
 assembly ("memory-safe") {
        // load the free memory pointer value
        let pointer := mload(0x40)

        // Define length of base (Bsize)
        mstore(pointer, 0x20)
        // Define the exponent size (Esize)
        mstore(add(pointer, 0x20), 0x20)
        // Define the modulus size (Msize)
        mstore(add(pointer, 0x40), 0x20)
        // Define variables base (B)
        mstore(add(pointer, 0x60), self)
        // Define the exponent (E)
        mstore(add(pointer, 0x80), pp1div4)
        // We save the point of the last argument, it will be override by the result
        // of the precompile call in order to avoid paying for the memory expansion properly
        let _result := add(pointer, 0xa0)
        // Define the modulus (M)
        mstore(_result, p)

        // Call the precompiled ModExp (0x05) https://www.evm.codes/precompiled#0x05
        if iszero(
            staticcall(
                not(0), // amount of gas to send
                MODEXP_PRECOMPILE, // target
                pointer, // argsOffset
                0xc0, // argsSize (6 * 32 bytes)
                _result, // retOffset (we override M to avoid paying for the memory expansion)
                0x20 // retSize (32 bytes)
            )
        ) { revert(0, 0) }

  result := mload(_result)
//  result :=addmod(result,0,p)
 }
   if(mulmod(result,result,p)!=self){
     result=_NOTSQUARE;
   }
  
   return result;
}
    /**
     * /* @dev Convert from affine rep to XYZZ rep
     */
    function ecAff_SetZZ(uint256 x0, uint256 y0) internal pure returns (uint256[4] memory P) {
        unchecked {
            P[2] = 1; //ZZ
            P[3] = 1; //ZZZ
            P[0] = x0;
            P[1] = y0;
        }
    }

    function ec_Decompress(uint256 x, uint256 parity) internal view returns(uint256 y){ 

        uint256 y2=mulmod(x,mulmod(x,x,p),p);//x3
        y2=addmod(b,addmod(y2,mulmod(x,a,p),p),p);//x3+ax+b

        y=SqrtMod(y2);
        if(y==_NOTSQUARE){
           return _NOTONCURVE;
        }
        if((y&1)!=(parity&1)){
            y=p-y;
        }
    }

    /**
     * /* @dev Convert from XYZZ rep to affine rep
     */
    /*    https://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz-3.html#addition-add-2008-s*/
    function ecZZ_SetAff(uint256 x, uint256 y, uint256 zz, uint256 zzz) internal view returns (uint256 x1, uint256 y1) {
        uint256 zzzInv = FCL_pModInv(zzz); //1/zzz
        y1 = mulmod(y, zzzInv, p); //Y/zzz
        uint256 _b = mulmod(zz, zzzInv, p); //1/z
        zzzInv = mulmod(_b, _b, p); //1/zz
        x1 = mulmod(x, zzzInv, p); //X/zz
    }

    /**
     * /* @dev Sutherland2008 doubling
     */
    /* The "dbl-2008-s-1" doubling formulas */

    function ecZZ_Dbl(uint256 x, uint256 y, uint256 zz, uint256 zzz)
        internal
        pure
        returns (uint256 P0, uint256 P1, uint256 P2, uint256 P3)
    {
        unchecked {
            assembly {
                P0 := mulmod(2, y, p) //U = 2*Y1
                P2 := mulmod(P0, P0, p) // V=U^2
                P3 := mulmod(x, P2, p) // S = X1*V
                P1 := mulmod(P0, P2, p) // W=UV
                P2 := mulmod(P2, zz, p) //zz3=V*ZZ1
                zz := mulmod(3, mulmod(addmod(x, sub(p, zz), p), addmod(x, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1)
                P0 := addmod(mulmod(zz, zz, p), mulmod(minus_2, P3, p), p) //X3=M^2-2S
                x := mulmod(zz, addmod(P3, sub(p, P0), p), p) //M(S-X3)
                P3 := mulmod(P1, zzz, p) //zzz3=W*zzz1
                P1 := addmod(x, sub(p, mulmod(P1, y, p)), p) //Y3= M(S-X3)-W*Y1
            }
        }
        return (P0, P1, P2, P3);
    }

    /**
     * @dev Sutherland2008 add a ZZ point with a normalized point and greedy formulae
     * warning: assume that P1(x1,y1)!=P2(x2,y2), true in multiplication loop with prime order (cofactor 1)
     */

    function ecZZ_AddN(uint256 x1, uint256 y1, uint256 zz1, uint256 zzz1, uint256 x2, uint256 y2)
        internal
        pure
        returns (uint256 P0, uint256 P1, uint256 P2, uint256 P3)
    {
        unchecked {
            if (y1 == 0) {
                return (x2, y2, 1, 1);
            }

            assembly {
                y1 := sub(p, y1)
                y2 := addmod(mulmod(y2, zzz1, p), y1, p)
                x2 := addmod(mulmod(x2, zz1, p), sub(p, x1), p)
                P0 := mulmod(x2, x2, p) //PP = P^2
                P1 := mulmod(P0, x2, p) //PPP = P*PP
                P2 := mulmod(zz1, P0, p) ////ZZ3 = ZZ1*PP
                P3 := mulmod(zzz1, P1, p) ////ZZZ3 = ZZZ1*PPP
                zz1 := mulmod(x1, P0, p) //Q = X1*PP
                P0 := addmod(addmod(mulmod(y2, y2, p), sub(p, P1), p), mulmod(minus_2, zz1, p), p) //R^2-PPP-2*Q
                P1 := addmod(mulmod(addmod(zz1, sub(p, P0), p), y2, p), mulmod(y1, P1, p), p) //R*(Q-X3)
            }
            //end assembly
        } //end unchecked
        return (P0, P1, P2, P3);
    }

    /**
     * @dev Return the zero curve in XYZZ coordinates.
     */
    function ecZZ_SetZero() internal pure returns (uint256 x, uint256 y, uint256 zz, uint256 zzz) {
        return (0, 0, 0, 0);
    }
    /**
     * @dev Check if point is the neutral of the curve
     */

    // uint256 x0, uint256 y0, uint256 zz0, uint256 zzz0
    function ecZZ_IsZero(uint256, uint256 y0, uint256, uint256) internal pure returns (bool) {
        return y0 == 0;
    }
    /**
     * @dev Return the zero curve in affine coordinates. Compatible with the double formulae (no special case)
     */

    function ecAff_SetZero() internal pure returns (uint256 x, uint256 y) {
        return (0, 0);
    }

    /**
     * @dev Check if the curve is the zero curve in affine rep.
     */
    // uint256 x, uint256 y)
    function ecAff_IsZero(uint256, uint256 y) internal pure returns (bool flag) {
        return (y == 0);
    }

    /**
     * @dev Check if a point in affine coordinates is on the curve (reject Neutral that is indeed on the curve).
     */
    function ecAff_isOnCurve(uint256 x, uint256 y) internal pure returns (bool) {
        if (x >= p || y >= p || ((x == 0) && (y == 0))) {
            return false;
        }
        unchecked {
            uint256 LHS = mulmod(y, y, p); // y^2
            uint256 RHS = addmod(mulmod(mulmod(x, x, p), x, p), mulmod(x, a, p), p); // x^3+ax
            RHS = addmod(RHS, b, p); // x^3 + a*x + b

            return LHS == RHS;
        }
    }

    /**
     * @dev Add two elliptic curve points in affine coordinates. Deal with P=Q
     */

    function ecAff_add(uint256 x0, uint256 y0, uint256 x1, uint256 y1) internal view returns (uint256, uint256) {
        uint256 zz0;
        uint256 zzz0;

        if (ecAff_IsZero(x0, y0)) return (x1, y1);
        if (ecAff_IsZero(x1, y1)) return (x0, y0);
        if((x0==x1)&&(y0==y1)) {
            (x0, y0, zz0, zzz0) = ecZZ_Dbl(x0, y0,1,1);
        }
        else{
            (x0, y0, zz0, zzz0) = ecZZ_AddN(x0, y0, 1, 1, x1, y1);
        }

        return ecZZ_SetAff(x0, y0, zz0, zzz0);
    }

    /**
     * @dev Computation of uG+vQ using Strauss-Shamir's trick, G basepoint, Q public key
     *       Returns only x for ECDSA use            
     *      */
    function ecZZ_mulmuladd_S_asm(
        uint256 Q0,
        uint256 Q1, //affine rep for input point Q
        uint256 scalar_u,
        uint256 scalar_v
    ) internal view returns (uint256 X) {
        uint256 zz;
        uint256 zzz;
        uint256 Y;
        uint256 index = 255;
        uint256 H0;
        uint256 H1;

        unchecked {
            if (scalar_u == 0 && scalar_v == 0) return 0;

            (H0, H1) = ecAff_add(gx, gy, Q0, Q1); 
            if((H0==0)&&(H1==0))//handling Q=-G
            {
                scalar_u=addmod(scalar_u, n-scalar_v, n);
                scalar_v=0;
                if (scalar_u == 0 && scalar_v == 0) return 0;
            }
            assembly {
                for { let T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) } eq(T4, 0) {
                    index := sub(index, 1)
                    T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))
                } {}
                zz := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))

                if eq(zz, 1) {
                    X := gx
                    Y := gy
                }
                if eq(zz, 2) {
                    X := Q0
                    Y := Q1
                }
                if eq(zz, 3) {
                    X := H0
                    Y := H1
                }

                index := sub(index, 1)
                zz := 1
                zzz := 1

                for {} gt(minus_1, index) { index := sub(index, 1) } {
                    // inlined EcZZ_Dbl
                    let T1 := mulmod(2, Y, p) //U = 2*Y1, y free
                    let T2 := mulmod(T1, T1, p) // V=U^2
                    let T3 := mulmod(X, T2, p) // S = X1*V
                    T1 := mulmod(T1, T2, p) // W=UV
                    let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1)
                    zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                    zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                    X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                    T2 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S)
                    Y := addmod(mulmod(T1, Y, p), T2, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to avoid a sub in ecAdd

                    {
                        //value of dibit
                        T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))

                        if iszero(T4) {
                            Y := sub(p, Y) //restore the -Y inversion
                            continue
                        } // if T4!=0

                        if eq(T4, 1) {
                            T1 := gx
                            T2 := gy
                        }
                        if eq(T4, 2) {
                            T1 := Q0
                            T2 := Q1
                        }
                        if eq(T4, 3) {
                            T1 := H0
                            T2 := H1
                        }
                        if iszero(zz) {
                            X := T1
                            Y := T2
                            zz := 1
                            zzz := 1
                            continue
                        }
                        // inlined EcZZ_AddN

                        //T3:=sub(p, Y)
                        //T3:=Y
                        let y2 := addmod(mulmod(T2, zzz, p), Y, p) //R
                        T2 := addmod(mulmod(T1, zz, p), sub(p, X), p) //P

                        //special extremely rare case accumulator where EcAdd is replaced by EcDbl, no need to optimize this
                        //todo : construct edge vector case
                        if iszero(y2) {
                            if iszero(T2) {
                                T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free
                                T2 := mulmod(T1, T1, p) // V=U^2
                                T3 := mulmod(X, T2, p) // S = X1*V

                                T1 := mulmod(T1, T2, p) // W=UV
                                y2 := mulmod(addmod(X, zz, p), addmod(X, sub(p, zz), p), p) //(X-ZZ)(X+ZZ)
                                T4 := mulmod(3, y2, p) //M=3*(X-ZZ)(X+ZZ)

                                zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                                zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                                X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                                T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3)

                                Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1

                                continue
                            }
                        }

                        T4 := mulmod(T2, T2, p) //PP
                        let TT1 := mulmod(T4, T2, p) //PPP, this one could be spared, but adding this register spare gas
                        zz := mulmod(zz, T4, p)
                        zzz := mulmod(zzz, TT1, p) //zz3=V*ZZ1
                        let TT2 := mulmod(X, T4, p)
                        T4 := addmod(addmod(mulmod(y2, y2, p), sub(p, TT1), p), mulmod(minus_2, TT2, p), p)
                        Y := addmod(mulmod(addmod(TT2, sub(p, T4), p), y2, p), mulmod(Y, TT1, p), p)

                        X := T4
                    }
                } //end loop
                let T := mload(0x40)
                mstore(add(T, 0x60), zz)
                //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz);
                //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using precompile:
                // Define length of base, exponent and modulus. 0x20 == 32 bytes
                mstore(T, 0x20)
                mstore(add(T, 0x20), 0x20)
                mstore(add(T, 0x40), 0x20)
                // Define variables base, exponent and modulus
                //mstore(add(pointer, 0x60), u)
                mstore(add(T, 0x80), minus_2)
                mstore(add(T, 0xa0), p)

                // Call the precompiled contract 0x05 = ModExp
                if iszero(staticcall(not(0), 0x05, T, 0xc0, T, 0x20)) { revert(0, 0) }

                //Y:=mulmod(Y,zzz,p)//Y/zzz
                //zz :=mulmod(zz, mload(T),p) //1/z
                //zz:= mulmod(zz,zz,p) //1/zz
                X := mulmod(X, mload(T), p) //X/zz
            } //end assembly
        } //end unchecked

        return X;
    }


    /**
     * @dev Computation of uG+vQ using Strauss-Shamir's trick, G basepoint, Q public key
     *       Returns affine representation of point (normalized)       
     *      */
    function ecZZ_mulmuladd(
        uint256 Q0,
        uint256 Q1, //affine rep for input point Q
        uint256 scalar_u,
        uint256 scalar_v
    ) internal view returns (uint256 X, uint256 Y) {
        uint256 zz;
        uint256 zzz;
        uint256 index = 255;
        uint256[6] memory T;
        uint256[2] memory H;
 
        unchecked {
            if (scalar_u == 0 && scalar_v == 0) return (0,0);

            (H[0], H[1]) = ecAff_add(gx, gy, Q0, Q1); //will not work if Q=P, obvious forbidden private key

            assembly {
                for { let T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) } eq(T4, 0) {
                    index := sub(index, 1)
                    T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))
                } {}
                zz := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))

                if eq(zz, 1) {
                    X := gx
                    Y := gy
                }
                if eq(zz, 2) {
                    X := Q0
                    Y := Q1
                }
                if eq(zz, 3) {
                    Y := mload(add(H,32))
                    X := mload(H)
                }

                index := sub(index, 1)
                zz := 1
                zzz := 1

                for {} gt(minus_1, index) { index := sub(index, 1) } {
                    // inlined EcZZ_Dbl
                    let T1 := mulmod(2, Y, p) //U = 2*Y1, y free
                    let T2 := mulmod(T1, T1, p) // V=U^2
                    let T3 := mulmod(X, T2, p) // S = X1*V
                    T1 := mulmod(T1, T2, p) // W=UV
                    let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1)
                    zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                    zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                    X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                    T2 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S)
                    Y := addmod(mulmod(T1, Y, p), T2, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to avoid a sub in ecAdd

                    {
                        //value of dibit
                        T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1))

                        if iszero(T4) {
                            Y := sub(p, Y) //restore the -Y inversion
                            continue
                        } // if T4!=0

                        if eq(T4, 1) {
                            T1 := gx
                            T2 := gy
                        }
                        if eq(T4, 2) {
                            T1 := Q0
                            T2 := Q1
                        }
                        if eq(T4, 3) {
                            T1 := mload(H)
                            T2 := mload(add(H,32))
                        }
                        if iszero(zz) {
                            X := T1
                            Y := T2
                            zz := 1
                            zzz := 1
                            continue
                        }
                        // inlined EcZZ_AddN

                        //T3:=sub(p, Y)
                        //T3:=Y
                        let y2 := addmod(mulmod(T2, zzz, p), Y, p) //R
                        T2 := addmod(mulmod(T1, zz, p), sub(p, X), p) //P

                        //special extremely rare case accumulator where EcAdd is replaced by EcDbl, no need to optimize this
                        //todo : construct edge vector case
                        if iszero(y2) {
                            if iszero(T2) {
                                T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free
                                T2 := mulmod(T1, T1, p) // V=U^2
                                T3 := mulmod(X, T2, p) // S = X1*V

                                T1 := mulmod(T1, T2, p) // W=UV
                                y2 := mulmod(addmod(X, zz, p), addmod(X, sub(p, zz), p), p) //(X-ZZ)(X+ZZ)
                                T4 := mulmod(3, y2, p) //M=3*(X-ZZ)(X+ZZ)

                                zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                                zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                                X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                                T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3)

                                Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1

                                continue
                            }
                        }

                        T4 := mulmod(T2, T2, p) //PP
                        let TT1 := mulmod(T4, T2, p) //PPP, this one could be spared, but adding this register spare gas
                        zz := mulmod(zz, T4, p)
                        zzz := mulmod(zzz, TT1, p) //zz3=V*ZZ1
                        let TT2 := mulmod(X, T4, p)
                        T4 := addmod(addmod(mulmod(y2, y2, p), sub(p, TT1), p), mulmod(minus_2, TT2, p), p)
                        Y := addmod(mulmod(addmod(TT2, sub(p, T4), p), y2, p), mulmod(Y, TT1, p), p)

                        X := T4
                    }
                } //end loop
                mstore(add(T, 0x60), zzz)
                //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz);
                //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using precompile:
                // Define length of base, exponent and modulus. 0x20 == 32 bytes
                mstore(T, 0x20)
                mstore(add(T, 0x20), 0x20)
                mstore(add(T, 0x40), 0x20)
                // Define variables base, exponent and modulus
                //mstore(add(pointer, 0x60), u)
                mstore(add(T, 0x80), minus_2)
                mstore(add(T, 0xa0), p)

                // Call the precompiled contract 0x05 = ModExp
                if iszero(staticcall(not(0), 0x05, T, 0xc0, T, 0x20)) { revert(0, 0) }

                Y:=mulmod(Y,mload(T),p)//Y/zzz
                zz :=mulmod(zz, mload(T),p) //1/z
                zz:= mulmod(zz,zz,p) //1/zz
                X := mulmod(X, zz, p) //X/zz
            } //end assembly
        } //end unchecked

        return (X,Y);
    }

    //8 dimensions Shamir's trick, using precomputations stored in Shamir8,  stored as Bytecode of an external
    //contract at given address dataPointer
    //(thx to Lakhdar https://github.com/Kelvyne for EVM storage explanations and tricks)
    // the external tool to generate tables from public key is in the /sage directory
    function ecZZ_mulmuladd_S8_extcode(uint256 scalar_u, uint256 scalar_v, address dataPointer)
        internal view
        returns (uint256 X /*, uint Y*/ )
    {
        unchecked {
            uint256 zz; // third and  coordinates of the point

            uint256[6] memory T;
            zz = 256; //start index

            while (T[0] == 0) {
                zz = zz - 1;
                //tbd case of msb octobit is null
                T[0] = 64
                    * (
                        128 * ((scalar_v >> zz) & 1) + 64 * ((scalar_v >> (zz - 64)) & 1)
                            + 32 * ((scalar_v >> (zz - 128)) & 1) + 16 * ((scalar_v >> (zz - 192)) & 1)
                            + 8 * ((scalar_u >> zz) & 1) + 4 * ((scalar_u >> (zz - 64)) & 1)
                            + 2 * ((scalar_u >> (zz - 128)) & 1) + ((scalar_u >> (zz - 192)) & 1)
                    );
            }
            assembly {
                extcodecopy(dataPointer, T, mload(T), 64)
                let index := sub(zz, 1)
                X := mload(T)
                let Y := mload(add(T, 32))
                let zzz := 1
                zz := 1

                //loop over 1/4 of scalars thx to Shamir's trick over 8 points
                for {} gt(index, 191) { index := add(index, 191) } {
                    //inline Double
                    {
                        let TT1 := mulmod(2, Y, p) //U = 2*Y1, y free
                        let T2 := mulmod(TT1, TT1, p) // V=U^2
                        let T3 := mulmod(X, T2, p) // S = X1*V
                        let T1 := mulmod(TT1, T2, p) // W=UV
                        let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1)
                        zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                        zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                        X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                        //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3)
                        let T5 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S)

                        //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p  )//Y3= M(S-X3)-W*Y1
                        Y := addmod(mulmod(T1, Y, p), T5, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to avoid a sub in ecAdd

                        /* compute element to access in precomputed table */
                    }
                    {
                        let T4 := add(shl(13, and(shr(index, scalar_v), 1)), shl(9, and(shr(index, scalar_u), 1)))
                        let index2 := sub(index, 64)
                        let T3 :=
                            add(T4, add(shl(12, and(shr(index2, scalar_v), 1)), shl(8, and(shr(index2, scalar_u), 1))))
                        let index3 := sub(index2, 64)
                        let T2 :=
                            add(T3, add(shl(11, and(shr(index3, scalar_v), 1)), shl(7, and(shr(index3, scalar_u), 1))))
                        index := sub(index3, 64)
                        let T1 :=
                            add(T2, add(shl(10, and(shr(index, scalar_v), 1)), shl(6, and(shr(index, scalar_u), 1))))

                        //tbd: check validity of formulae with (0,1) to remove conditional jump
                        if iszero(T1) {
                            Y := sub(p, Y)

                            continue
                        }
                        extcodecopy(dataPointer, T, T1, 64)
                    }

                    {
                        /* Access to precomputed table using extcodecopy hack */

                        // inlined EcZZ_AddN
                        if iszero(zz) {
                            X := mload(T)
                            Y := mload(add(T, 32))
                            zz := 1
                            zzz := 1

                            continue
                        }

                        let y2 := addmod(mulmod(mload(add(T, 32)), zzz, p), Y, p)
                        let T2 := addmod(mulmod(mload(T), zz, p), sub(p, X), p)

                        //special case ecAdd(P,P)=EcDbl
                        if iszero(y2) {
                            if iszero(T2) {
                                let T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free
                                T2 := mulmod(T1, T1, p) // V=U^2
                                let T3 := mulmod(X, T2, p) // S = X1*V

                                T1 := mulmod(T1, T2, p) // W=UV
                                y2 := mulmod(addmod(X, zz, p), addmod(X, sub(p, zz), p), p) //(X-ZZ)(X+ZZ)
                                let T4 := mulmod(3, y2, p) //M=3*(X-ZZ)(X+ZZ)

                                zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                                zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                                X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                                T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3)

                                Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1

                                continue
                            }
                        }

                        let T4 := mulmod(T2, T2, p)
                        let T1 := mulmod(T4, T2, p) //
                        zz := mulmod(zz, T4, p)
                        //zzz3=V*ZZ1
                        zzz := mulmod(zzz, T1, p) // W=UV/
                        let zz1 := mulmod(X, T4, p)
                        X := addmod(addmod(mulmod(y2, y2, p), sub(p, T1), p), mulmod(minus_2, zz1, p), p)
                        Y := addmod(mulmod(addmod(zz1, sub(p, X), p), y2, p), mulmod(Y, T1, p), p)
                    }
                } //end loop
                mstore(add(T, 0x60), zz)

                //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz);
                //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using precompile:
                // Define length of base, exponent and modulus. 0x20 == 32 bytes
                mstore(T, 0x20)
                mstore(add(T, 0x20), 0x20)
                mstore(add(T, 0x40), 0x20)
                // Define variables base, exponent and modulus
                //mstore(add(pointer, 0x60), u)
                mstore(add(T, 0x80), minus_2)
                mstore(add(T, 0xa0), p)

                // Call the precompiled contract 0x05 = ModExp
                if iszero(staticcall(not(0), 0x05, T, 0xc0, T, 0x20)) { revert(0, 0) }

                zz := mload(T)
                X := mulmod(X, zz, p) //X/zz
            }
        } //end unchecked
    }

   

    // improving the extcodecopy trick : append array at end of contract
    function ecZZ_mulmuladd_S8_hackmem(uint256 scalar_u, uint256 scalar_v, uint256 dataPointer)
        internal view
        returns (uint256 X /*, uint Y*/ )
    {
        uint256 zz; // third and  coordinates of the point

        uint256[6] memory T;
        zz = 256; //start index

        unchecked {
            while (T[0] == 0) {
                zz = zz - 1;
                //tbd case of msb octobit is null
                T[0] = 64
                    * (
                        128 * ((scalar_v >> zz) & 1) + 64 * ((scalar_v >> (zz - 64)) & 1)
                            + 32 * ((scalar_v >> (zz - 128)) & 1) + 16 * ((scalar_v >> (zz - 192)) & 1)
                            + 8 * ((scalar_u >> zz) & 1) + 4 * ((scalar_u >> (zz - 64)) & 1)
                            + 2 * ((scalar_u >> (zz - 128)) & 1) + ((scalar_u >> (zz - 192)) & 1)
                    );
            }
            assembly {
                codecopy(T, add(mload(T), dataPointer), 64)
                X := mload(T)
                let Y := mload(add(T, 32))
                let zzz := 1
                zz := 1

                //loop over 1/4 of scalars thx to Shamir's trick over 8 points
                for { let index := 254 } gt(index, 191) { index := add(index, 191) } {
                    let T1 := mulmod(2, Y, p) //U = 2*Y1, y free
                    let T2 := mulmod(T1, T1, p) // V=U^2
                    let T3 := mulmod(X, T2, p) // S = X1*V
                    T1 := mulmod(T1, T2, p) // W=UV
                    let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1)
                    zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1
                    zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free

                    X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S
                    //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3)
                    T2 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S)

                    //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p  )//Y3= M(S-X3)-W*Y1
                    Y := addmod(mulmod(T1, Y, p), T2, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to avoid a sub in ecAdd

                    /* compute element to access in precomputed table */
                    T4 := add(shl(13, and(shr(index, scalar_v), 1)), shl(9, and(shr(index, scalar_u), 1)))
                    index := sub(index, 64)
                    T4 := add(T4, add(shl(12, and(shr(index, scalar_v), 1)), shl(8, and(shr(index, scalar_u), 1))))
                    index := sub(index, 64)
                    T4 := add(T4, add(shl(11, and(shr(index, scalar_v), 1)), shl(7, and(shr(index, scalar_u), 1))))
                    index := sub(index, 64)
                    T4 := add(T4, add(shl(10, and(shr(index, scalar_v), 1)), shl(6, and(shr(index, scalar_u), 1))))
                    //index:=add(index,192), restore index, interleaved with loop

                    //tbd: check validity of formulae with (0,1) to remove conditional jump
                    if iszero(T4) {
                        Y := sub(p, Y)

                        continue
                    }
                    {
                        /* Access to precomputed table using extcodecopy hack */
                        codecopy(T, add(T4, dataPointer), 64)

                        // inlined EcZZ_AddN

                        let y2 := addmod(mulmod(mload(add(T, 32)), zzz, p), Y, p)
                        T2 := addmod(mulmod(mload(T), zz, p), sub(p, X), p)
                        T4 := mulmod(T2, T2, p)
                        T1 := mulmod(T4, T2, p)
                        T2 := mulmod(zz, T4, p) // W=UV
                        zzz := mulmod(zzz, T1, p) //zz3=V*ZZ1
                        let zz1 := mulmod(X, T4, p)
                        T4 := addmod(addmod(mulmod(y2, y2, p), sub(p, T1), p), mulmod(minus_2, zz1, p), p)
                        Y := addmod(mulmod(addmod(zz1, sub(p, T4), p), y2, p), mulmod(Y, T1, p), p)
                        zz := T2
                        X := T4
                    }
                } //end loop
                mstore(add(T, 0x60), zz)

                //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz);
                //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using precompile:
                // Define length of base, exponent and modulus. 0x20 == 32 bytes
                mstore(T, 0x20)
                mstore(add(T, 0x20), 0x20)
                mstore(add(T, 0x40), 0x20)
                // Define variables base, exponent and modulus
                //mstore(add(pointer, 0x60), u)
                mstore(add(T, 0x80), minus_2)
                mstore(add(T, 0xa0), p)

                // Call the precompiled contract 0x05 = ModExp
                if iszero(staticcall(not(0), 0x05, T, 0xc0, T, 0x20)) { revert(0, 0) }

                zz := mload(T)
                X := mulmod(X, zz, p) //X/zz
            }
        } //end unchecked
    }


    /**
     * @dev ECDSA verification using a precomputed table of multiples of P and Q stored in contract at address Shamir8
     *     generation of contract bytecode for precomputations is done using sagemath code
     *     (see sage directory, WebAuthn_precompute.sage)
     */

    /**
     * @dev ECDSA verification using a precomputed table of multiples of P and Q appended at end of contract at address endcontract
     *     generation of contract bytecode for precomputations is done using sagemath code
     *     (see sage directory, WebAuthn_precompute.sage)
     */

    function ecdsa_precomputed_hackmem(bytes32 message, uint256[2] calldata rs, uint256 endcontract)
        internal view
        returns (bool)
    {
        uint256 r = rs[0];
        uint256 s = rs[1];
        if (r == 0 || r >= n || s == 0 || s >= n) {
            return false;
        }
        /* Q is pushed via bytecode assumed to be correct
        if (!isOnCurve(Q[0], Q[1])) {
            return false;
        }*/

        uint256 sInv = FCL_nModInv(s);
        uint256 X;

        //Shamir 8 dimensions
        X = ecZZ_mulmuladd_S8_hackmem(mulmod(uint256(message), sInv, n), mulmod(r, sInv, n), endcontract);

        assembly {
            X := addmod(X, sub(n, r), n)
        }
        return X == 0;
    } //end  ecdsa_precomputed_verify()



} //EOF

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

pragma solidity ^0.8.20;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     * See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        return _encode(data, _TABLE, true);
    }

    /**
     * @dev Converts a `bytes` to its Bytes64Url `string` representation.
     * Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648].
     */
    function encodeURL(bytes memory data) internal pure returns (string memory) {
        return _encode(data, _TABLE_URL, false);
    }

    /**
     * @dev Internal table-agnostic conversion
     */
    function _encode(bytes memory data, string memory table, bool withPadding) private pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
        // multiplied by 4 so that it leaves room for padding the last chunk
        // - `data.length + 2`  -> Prepare for division rounding up
        // - `/ 3`              -> Number of 3-bytes chunks (rounded up)
        // - `4 *`              -> 4 characters for each chunk
        // This is equivalent to: 4 * Math.ceil(data.length / 3)
        //
        // If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
        // opposed to when padding is required to fill the last chunk.
        // - `4 * data.length`  -> 4 characters for each chunk
        // - ` + 2`             -> Prepare for division rounding up
        // - `/ 3`              -> Number of 3-bytes chunks (rounded up)
        // This is equivalent to: Math.ceil((4 * data.length) / 3)
        uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;

        string memory result = new string(resultLength);

        assembly ("memory-safe") {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 0x20)
            let dataPtr := data
            let endPtr := add(data, mload(data))

            // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
            // set it to zero to make sure no dirty bytes are read in that section.
            let afterPtr := add(endPtr, 0x20)
            let afterCache := mload(afterPtr)
            mstore(afterPtr, 0x00)

            // Run over the input, 3 bytes at a time
            for {

            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 byte (24 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F to bitmask the least significant 6 bits.
                // Use this as an index into the lookup table, mload an entire word
                // so the desired character is in the least significant byte, and
                // mstore8 this least significant byte into the result and continue.

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // Reset the value that was cached
            mstore(afterPtr, afterCache)

            if withPadding {
                // When data `bytes` is not exactly 3 bytes long
                // it is padded with `=` characters at the end
                switch mod(mload(data), 3)
                case 1 {
                    mstore8(sub(resultPtr, 1), 0x3d)
                    mstore8(sub(resultPtr, 2), 0x3d)
                }
                case 2 {
                    mstore8(sub(resultPtr, 1), 0x3d)
                }
            }
        }

        return result;
    }
}

File 61 of 63 : LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Goated string storage struct that totally MOGs, no cap, fr.
    /// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
    /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
    struct StringStorage {
        bytes32 _spacer;
    }

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

    /// @dev The length of the output is too small to contain all the hex digits.
    error HexLengthInsufficient();

    /// @dev The length of the string is more than 32 bytes.
    error TooBigForSmallString();

    /// @dev The input string must be a 7-bit ASCII.
    error StringNot7BitASCII();

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

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;

    /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;

    /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
    uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;

    /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;

    /// @dev Lookup for '0123456789'.
    uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;

    /// @dev Lookup for '0123456789abcdefABCDEF'.
    uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;

    /// @dev Lookup for '01234567'.
    uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;

    /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
    uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;

    /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
    uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;

    /// @dev Lookup for ' \t\n\r\x0b\x0c'.
    uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;

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

    /// @dev Sets the value of the string storage `$` to `s`.
    function set(StringStorage storage $, string memory s) internal {
        LibBytes.set(bytesStorage($), bytes(s));
    }

    /// @dev Sets the value of the string storage `$` to `s`.
    function setCalldata(StringStorage storage $, string calldata s) internal {
        LibBytes.setCalldata(bytesStorage($), bytes(s));
    }

    /// @dev Sets the value of the string storage `$` to the empty string.
    function clear(StringStorage storage $) internal {
        delete $._spacer;
    }

    /// @dev Returns whether the value stored is `$` is the empty string "".
    function isEmpty(StringStorage storage $) internal view returns (bool) {
        return uint256($._spacer) & 0xff == uint256(0);
    }

    /// @dev Returns the length of the value stored in `$`.
    function length(StringStorage storage $) internal view returns (uint256) {
        return LibBytes.length(bytesStorage($));
    }

    /// @dev Returns the value stored in `$`.
    function get(StringStorage storage $) internal view returns (string memory) {
        return string(LibBytes.get(bytesStorage($)));
    }

    /// @dev Helper to cast `$` to a `BytesStorage`.
    function bytesStorage(StringStorage storage $)
        internal
        pure
        returns (LibBytes.BytesStorage storage casted)
    {
        /// @solidity memory-safe-assembly
        assembly {
            casted.slot := $.slot
        }
    }

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

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits.
            result := add(mload(0x40), 0x80)
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

            let end := result // Cache the end of the memory to calculate the length later.
            let w := not(0) // Tsk.
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let temp := value } 1 {} {
                result := add(result, w) // `sub(result, 1)`.
                // Store the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(result, add(48, mod(temp, 10)))
                temp := div(temp, 10) // Keep dividing `temp` until zero.
                if iszero(temp) { break }
            }
            let n := sub(end, result)
            result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory result) {
        if (value >= 0) return toString(uint256(value));
        unchecked {
            result = toString(~uint256(value) + 1);
        }
        /// @solidity memory-safe-assembly
        assembly {
            // We still have some spare memory space on the left,
            // as we have allocated 3 words (96 bytes) for up to 78 digits.
            let n := mload(result) // Load the string length.
            mstore(result, 0x2d) // Store the '-' character.
            result := sub(result, 1) // Move back the string pointer by a byte.
            mstore(result, add(n, 1)) // Update the string length.
        }
    }

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

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `byteCount` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `byteCount * 2 + 2` bytes.
    /// Reverts if `byteCount` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 byteCount)
        internal
        pure
        returns (string memory result)
    {
        result = toHexStringNoPrefix(value, byteCount);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `byteCount` bytes.
    /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `byteCount * 2` bytes.
    /// Reverts if `byteCount` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 byteCount)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes
            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
            // We add 0x20 to the total and round down to a multiple of 0x20.
            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
            result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

            let end := result // Cache the end to calculate the length later.
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let start := sub(result, add(byteCount, byteCount))
            let w := not(1) // Tsk.
            let temp := value
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for {} 1 {} {
                result := add(result, w) // `sub(result, 2)`.
                mstore8(add(result, 1), mload(and(temp, 15)))
                mstore8(result, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(result, start)) { break }
            }
            if temp {
                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                revert(0x1c, 0x04)
            }
            let n := sub(end, result)
            result := sub(result, 0x20)
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2 + 2` bytes.
    function toHexString(uint256 value) internal pure returns (string memory result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x".
    /// The output excludes leading "0" from the `toHexString` output.
    /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
    function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
            let n := add(mload(result), 2) // Compute the length.
            mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
            result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
            mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output excludes leading "0" from the `toHexStringNoPrefix` output.
    /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
    function toMinimalHexStringNoPrefix(uint256 value)
        internal
        pure
        returns (string memory result)
    {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
            let n := mload(result) // Get the length.
            result := add(result, o) // Move the pointer, accounting for leading zero.
            mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2` bytes.
    function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
            result := add(mload(0x40), 0x80)
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

            let end := result // Cache the end to calculate the length later.
            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.

            let w := not(1) // Tsk.
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let temp := value } 1 {} {
                result := add(result, w) // `sub(result, 2)`.
                mstore8(add(result, 1), mload(and(temp, 15)))
                mstore8(result, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }
            let n := sub(end, result)
            result := sub(result, 0x20)
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
    /// and the alphabets are capitalized conditionally according to
    /// https://eips.ethereum.org/EIPS/eip-55
    function toHexStringChecksummed(address value) internal pure returns (string memory result) {
        result = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(result, 0x22)
            let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
            let t := shl(240, 136) // `0b10001000 << 240`
            for { let i := 0 } 1 {} {
                mstore(add(i, i), mul(t, byte(i, hashed)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
            mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
            o := add(o, 0x20)
            mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    function toHexString(address value) internal pure returns (string memory result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            // Allocate memory.
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
            mstore(0x40, add(result, 0x80))
            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.

            result := add(result, 2)
            mstore(result, 40) // Store the length.
            let o := add(result, 0x20)
            mstore(add(o, 40), 0) // Zeroize the slot after the string.
            value := shl(96, value)
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let i := 0 } 1 {} {
                let p := add(o, add(i, i))
                let temp := byte(i, value)
                mstore8(add(p, 1), mload(and(temp, 15)))
                mstore8(p, mload(shr(4, temp)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexString(bytes memory raw) internal pure returns (string memory result) {
        result = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(raw)
            result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(result, add(n, n)) // Store the length of the output.

            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
            let o := add(result, 0x20)
            let end := add(raw, n)
            for {} iszero(eq(raw, end)) {} {
                raw := add(raw, 1)
                mstore8(add(o, 1), mload(and(mload(raw), 15)))
                mstore8(o, mload(and(shr(4, mload(raw)), 15)))
                o := add(o, 2)
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RUNE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of UTF characters in the string.
    function runeCount(string memory s) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                mstore(0x00, div(not(0), 255))
                mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
                let o := add(s, 0x20)
                let end := add(o, mload(s))
                for { result := 1 } 1 { result := add(result, 1) } {
                    o := add(o, byte(0, mload(shr(250, mload(o)))))
                    if iszero(lt(o, end)) { break }
                }
            }
        }
    }

    /// @dev Returns if this string is a 7-bit ASCII string.
    /// (i.e. all characters codes are in [0..127])
    function is7BitASCII(string memory s) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            let mask := shl(7, div(not(0), 255))
            let n := mload(s)
            if n {
                let o := add(s, 0x20)
                let end := add(o, n)
                let last := mload(end)
                mstore(end, 0)
                for {} 1 {} {
                    if and(mask, mload(o)) {
                        result := 0
                        break
                    }
                    o := add(o, 0x20)
                    if iszero(lt(o, end)) { break }
                }
                mstore(end, last)
            }
        }
    }

    /// @dev Returns if this string is a 7-bit ASCII string,
    /// AND all characters are in the `allowed` lookup.
    /// Note: If `s` is empty, returns true regardless of `allowed`.
    function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if mload(s) {
                let allowed_ := shr(128, shl(128, allowed))
                let o := add(s, 0x20)
                for { let end := add(o, mload(s)) } 1 {} {
                    result := and(result, shr(byte(0, mload(o)), allowed_))
                    o := add(o, 1)
                    if iszero(and(result, lt(o, end))) { break }
                }
            }
        }
    }

    /// @dev Converts the bytes in the 7-bit ASCII string `s` to
    /// an allowed lookup for use in `is7BitASCII(s, allowed)`.
    /// To save runtime gas, you can cache the result in an immutable variable.
    function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                let o := add(s, 0x20)
                for { let end := add(o, mload(s)) } 1 {} {
                    result := or(result, shl(byte(0, mload(o)), 1))
                    o := add(o, 1)
                    if iszero(lt(o, end)) { break }
                }
                if shr(128, result) {
                    mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   BYTE STRING OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance and bytecode compactness, byte string operations are restricted
    // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
    // Usage of byte string operations on charsets with runes spanning two or more bytes
    // can lead to undefined behavior.

    /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
    function replace(string memory subject, string memory needle, string memory replacement)
        internal
        pure
        returns (string memory)
    {
        return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(string memory subject, string memory needle, uint256 from)
        internal
        pure
        returns (uint256)
    {
        return LibBytes.indexOf(bytes(subject), bytes(needle), from);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
        return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(string memory subject, string memory needle, uint256 from)
        internal
        pure
        returns (uint256)
    {
        return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(string memory subject, string memory needle)
        internal
        pure
        returns (uint256)
    {
        return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
    }

    /// @dev Returns true if `needle` is found in `subject`, false otherwise.
    function contains(string memory subject, string memory needle) internal pure returns (bool) {
        return LibBytes.contains(bytes(subject), bytes(needle));
    }

    /// @dev Returns whether `subject` starts with `needle`.
    function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
        return LibBytes.startsWith(bytes(subject), bytes(needle));
    }

    /// @dev Returns whether `subject` ends with `needle`.
    function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
        return LibBytes.endsWith(bytes(subject), bytes(needle));
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
        return string(LibBytes.repeat(bytes(subject), times));
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(string memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (string memory)
    {
        return string(LibBytes.slice(bytes(subject), start, end));
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start) internal pure returns (string memory) {
        return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
    }

    /// @dev Returns all the indices of `needle` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory needle)
        internal
        pure
        returns (uint256[] memory)
    {
        return LibBytes.indicesOf(bytes(subject), bytes(needle));
    }

    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter)
        internal
        pure
        returns (string[] memory result)
    {
        bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
        /// @solidity memory-safe-assembly
        assembly {
            result := a
        }
    }

    /// @dev Returns a concatenated string of `a` and `b`.
    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
    function concat(string memory a, string memory b) internal pure returns (string memory) {
        return string(LibBytes.concat(bytes(a), bytes(b)));
    }

    /// @dev Returns a copy of the string in either lowercase or UPPERCASE.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function toCase(string memory subject, bool toUpper)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(subject)
            if n {
                result := mload(0x40)
                let o := add(result, 0x20)
                let d := sub(subject, result)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                for { let end := add(o, n) } 1 {} {
                    let b := byte(0, mload(add(d, o)))
                    mstore8(o, xor(and(shr(b, flags), 0x20), b))
                    o := add(o, 1)
                    if eq(o, end) { break }
                }
                mstore(result, n) // Store the length.
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
            }
        }
    }

    /// @dev Returns a string from a small bytes32 string.
    /// `s` must be null-terminated, or behavior will be undefined.
    function fromSmallString(bytes32 s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let n := 0
            for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
            mstore(result, n) // Store the length.
            let o := add(result, 0x20)
            mstore(o, s) // Store the bytes of the string.
            mstore(add(o, n), 0) // Zeroize the slot after the string.
            mstore(0x40, add(result, 0x40)) // Allocate memory.
        }
    }

    /// @dev Returns the small string, with all bytes after the first null byte zeroized.
    function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
            mstore(0x00, s)
            mstore(result, 0x00)
            result := mload(0x00)
        }
    }

    /// @dev Returns the string as a normalized null-terminated small string.
    function toSmallString(string memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(s)
            if iszero(lt(result, 33)) {
                mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
                revert(0x1c, 0x04)
            }
            result := shl(shl(3, sub(32, result)), mload(add(s, result)))
        }
    }

    /// @dev Returns a lowercased copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function lower(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, false);
    }

    /// @dev Returns an UPPERCASED copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function upper(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, true);
    }

    /// @dev Escapes the string to be used within HTML tags.
    function escapeHTML(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let end := add(s, mload(s))
            let o := add(result, 0x20)
            // Store the bytes of the packed offsets and strides into the scratch space.
            // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
            mstore(0x1f, 0x900094)
            mstore(0x08, 0xc0000000a6ab)
            // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
            mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
            for {} iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // Not in `["\"","'","&","<",">"]`.
                if iszero(and(shl(c, 1), 0x500000c400000000)) {
                    mstore8(o, c)
                    o := add(o, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(o, mload(and(t, 0x1f)))
                o := add(o, shr(5, t))
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
    function escapeJSON(string memory s, bool addDoubleQuotes)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let o := add(result, 0x20)
            if addDoubleQuotes {
                mstore8(o, 34)
                o := add(1, o)
            }
            // Store "\\u0000" in scratch space.
            // Store "0123456789abcdef" in scratch space.
            // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
            // into the scratch space.
            mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
            // Bitmask for detecting `["\"","\\"]`.
            let e := or(shl(0x22, 1), shl(0x5c, 1))
            for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                if iszero(lt(c, 0x20)) {
                    if iszero(and(shl(c, 1), e)) {
                        // Not in `["\"","\\"]`.
                        mstore8(o, c)
                        o := add(o, 1)
                        continue
                    }
                    mstore8(o, 0x5c) // "\\".
                    mstore8(add(o, 1), c)
                    o := add(o, 2)
                    continue
                }
                if iszero(and(shl(c, 1), 0x3700)) {
                    // Not in `["\b","\t","\n","\f","\d"]`.
                    mstore8(0x1d, mload(shr(4, c))) // Hex value.
                    mstore8(0x1e, mload(and(c, 15))) // Hex value.
                    mstore(o, mload(0x19)) // "\\u00XX".
                    o := add(o, 6)
                    continue
                }
                mstore8(o, 0x5c) // "\\".
                mstore8(add(o, 1), mload(add(c, 8)))
                o := add(o, 2)
            }
            if addDoubleQuotes {
                mstore8(o, 34)
                o := add(1, o)
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    function escapeJSON(string memory s) internal pure returns (string memory result) {
        result = escapeJSON(s, false);
    }

    /// @dev Encodes `s` so that it can be safely used in a URI,
    /// just like `encodeURIComponent` in JavaScript.
    /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
    /// See: https://datatracker.ietf.org/doc/html/rfc2396
    /// See: https://datatracker.ietf.org/doc/html/rfc3986
    function encodeURIComponent(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            // Store "0123456789ABCDEF" in scratch space.
            // Uppercased to be consistent with JavaScript's implementation.
            mstore(0x0f, 0x30313233343536373839414243444546)
            let o := add(result, 0x20)
            for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // If not in `[0-9A-Z-a-z-_.!~*'()]`.
                if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
                    mstore8(o, 0x25) // '%'.
                    mstore8(add(o, 1), mload(and(shr(4, c), 15)))
                    mstore8(add(o, 2), mload(and(c, 15)))
                    o := add(o, 3)
                    continue
                }
                mstore8(o, c)
                o := add(o, 1)
            }
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
        }
    }

    /// @dev Returns whether `a` equals `b`.
    function eq(string memory a, string memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
        }
    }

    /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
    function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // These should be evaluated on compile time, as far as possible.
            let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
            let x := not(or(m, or(b, add(m, and(b, m)))))
            let r := shl(7, iszero(iszero(shr(128, x))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
        }
    }

    /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
    /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
    function cmp(string memory a, string memory b) internal pure returns (int256) {
        return LibBytes.cmp(bytes(a), bytes(b));
    }

    /// @dev Packs a single string with its length into a single word.
    /// Returns `bytes32(0)` if the length is zero or greater than 31.
    function packOne(string memory a) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // We don't need to zero right pad the string,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes.
                    mload(add(a, 0x1f)),
                    // `length != 0 && length < 32`. Abuses underflow.
                    // Assumes that the length is valid and within the block gas limit.
                    lt(sub(mload(a), 1), 0x1f)
                )
        }
    }

    /// @dev Unpacks a string packed using {packOne}.
    /// Returns the empty string if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packOne}, the output behavior is undefined.
    function unpackOne(bytes32 packed) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40) // Grab the free memory pointer.
            mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(result, 0) // Zeroize the length slot.
            mstore(add(result, 0x1f), packed) // Store the length and bytes.
            mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
        }
    }

    /// @dev Packs two strings with their lengths into a single word.
    /// Returns `bytes32(0)` if combined length is zero or greater than 30.
    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLen := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    or( // Load the length and the bytes of `a` and `b`.
                    shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
                    // `totalLen != 0 && totalLen < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLen, mload(b)), 1), 0x1e)
                )
        }
    }

    /// @dev Unpacks strings packed using {packTwo}.
    /// Returns the empty strings if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packTwo}, the output behavior is undefined.
    function unpackTwo(bytes32 packed)
        internal
        pure
        returns (string memory resultA, string memory resultB)
    {
        /// @solidity memory-safe-assembly
        assembly {
            resultA := mload(0x40) // Grab the free memory pointer.
            resultB := add(resultA, 0x40)
            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
            mstore(0x40, add(resultB, 0x40))
            // Zeroize the length slots.
            mstore(resultA, 0)
            mstore(resultB, 0)
            // Store the lengths and bytes.
            mstore(add(resultA, 0x1f), packed)
            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
            // Right pad with zeroes.
            mstore(add(add(resultA, 0x20), mload(resultA)), 0)
            mstore(add(add(resultB, 0x20), mload(resultB)), 0)
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(string memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // Assumes that the string does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retUnpaddedSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the string is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retUnpaddedSize), 0)
            mstore(retStart, 0x20) // Store the return offset.
            // End the transaction, returning the string.
            return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
        }
    }

    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return ternary(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 {
            // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
            // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
            // taking advantage of the most significant (or "sign" bit) in two's complement representation.
            // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
            // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
            int256 mask = n >> 255;

            // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
            return uint256((n + mask) ^ mask);
        }
    }
}

File 63 of 63 : LibBytes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
    /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
    /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
    struct BytesStorage {
        bytes32 _spacer;
    }

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

    /// @dev The constant returned when the `search` is not found in the bytes.
    uint256 internal constant NOT_FOUND = type(uint256).max;

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

    /// @dev Sets the value of the bytes storage `$` to `s`.
    function set(BytesStorage storage $, bytes memory s) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(s)
            let packed := or(0xff, shl(8, n))
            for { let i := 0 } 1 {} {
                if iszero(gt(n, 0xfe)) {
                    i := 0x1f
                    packed := or(n, shl(8, mload(add(s, i))))
                    if iszero(gt(n, i)) { break }
                }
                let o := add(s, 0x20)
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    sstore(add(p, shr(5, i)), mload(add(o, i)))
                    i := add(i, 0x20)
                    if iszero(lt(i, n)) { break }
                }
                break
            }
            sstore($.slot, packed)
        }
    }

    /// @dev Sets the value of the bytes storage `$` to `s`.
    function setCalldata(BytesStorage storage $, bytes calldata s) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let packed := or(0xff, shl(8, s.length))
            for { let i := 0 } 1 {} {
                if iszero(gt(s.length, 0xfe)) {
                    i := 0x1f
                    packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
                    if iszero(gt(s.length, i)) { break }
                }
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
                    i := add(i, 0x20)
                    if iszero(lt(i, s.length)) { break }
                }
                break
            }
            sstore($.slot, packed)
        }
    }

    /// @dev Sets the value of the bytes storage `$` to the empty bytes.
    function clear(BytesStorage storage $) internal {
        delete $._spacer;
    }

    /// @dev Returns whether the value stored is `$` is the empty bytes "".
    function isEmpty(BytesStorage storage $) internal view returns (bool) {
        return uint256($._spacer) & 0xff == uint256(0);
    }

    /// @dev Returns the length of the value stored in `$`.
    function length(BytesStorage storage $) internal view returns (uint256 result) {
        result = uint256($._spacer);
        /// @solidity memory-safe-assembly
        assembly {
            let n := and(0xff, result)
            result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
        }
    }

    /// @dev Returns the value stored in `$`.
    function get(BytesStorage storage $) internal view returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let o := add(result, 0x20)
            let packed := sload($.slot)
            let n := shr(8, packed)
            for { let i := 0 } 1 {} {
                if iszero(eq(or(packed, 0xff), packed)) {
                    mstore(o, packed)
                    n := and(0xff, packed)
                    i := 0x1f
                    if iszero(gt(n, i)) { break }
                }
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    mstore(add(o, i), sload(add(p, shr(5, i))))
                    i := add(i, 0x20)
                    if iszero(lt(i, n)) { break }
                }
                break
            }
            mstore(result, n) // Store the length of the memory.
            mstore(add(o, n), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
        }
    }

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

    /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
    function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let needleLen := mload(needle)
            let replacementLen := mload(replacement)
            let d := sub(result, subject) // Memory difference.
            let i := add(subject, 0x20) // Subject bytes pointer.
            mstore(0x00, add(i, mload(subject))) // End of subject.
            if iszero(gt(needleLen, mload(subject))) {
                let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, needleLen), h)) {
                                mstore(add(i, d), t)
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let j := 0 } 1 {} {
                            mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
                            j := add(j, 0x20)
                            if iszero(lt(j, replacementLen)) { break }
                        }
                        d := sub(add(d, replacementLen), needleLen)
                        if needleLen {
                            i := add(i, needleLen)
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(add(i, d), t)
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
            }
            let end := mload(0x00)
            let n := add(sub(d, add(result, 0x20)), end)
            // Copy the rest of the bytes one word at a time.
            for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
            let o := add(i, d)
            mstore(o, 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(bytes memory subject, bytes memory needle, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := not(0) // Initialize to `NOT_FOUND`.
            for { let subjectLen := mload(subject) } 1 {} {
                if iszero(mload(needle)) {
                    result := from
                    if iszero(gt(from, subjectLen)) { break }
                    result := subjectLen
                    break
                }
                let needleLen := mload(needle)
                let subjectStart := add(subject, 0x20)

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
                let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
                let s := mload(add(needle, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }

                if iszero(lt(needleLen, 0x20)) {
                    for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, needleLen), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        if iszero(lt(subject, end)) { break }
                    }
                    break
                }
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
        return indexOf(subject, needle, 0);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let needleLen := mload(needle)
                if gt(needleLen, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), needleLen)
                if iszero(gt(fromMax, from)) { from := fromMax }

                let end := add(add(subject, 0x20), w)
                subject := add(add(subject, 0x20), from)
                if iszero(gt(subject, end)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                    if eq(keccak256(subject, needleLen), h) {
                        result := sub(subject, add(end, 1))
                        break
                    }
                    subject := add(subject, w) // `sub(subject, 1)`.
                    if iszero(gt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (uint256)
    {
        return lastIndexOf(subject, needle, type(uint256).max);
    }

    /// @dev Returns true if `needle` is found in `subject`, false otherwise.
    function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
        return indexOf(subject, needle) != NOT_FOUND;
    }

    /// @dev Returns whether `subject` starts with `needle`.
    function startsWith(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(needle)
            // Just using keccak256 directly is actually cheaper.
            let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
            result := lt(gt(n, mload(subject)), t)
        }
    }

    /// @dev Returns whether `subject` ends with `needle`.
    function endsWith(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(needle)
            let notInRange := gt(n, mload(subject))
            // `subject + 0x20 + max(subject.length - needle.length, 0)`.
            let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
            // Just using keccak256 directly is actually cheaper.
            result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(bytes memory subject, uint256 times)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(subject) // Subject length.
            if iszero(or(iszero(times), iszero(l))) {
                result := mload(0x40)
                subject := add(subject, 0x20)
                let o := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let j := 0 } 1 {} {
                        mstore(add(o, j), mload(add(subject, j)))
                        j := add(j, 0x20)
                        if iszero(lt(j, l)) { break }
                    }
                    o := add(o, l)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(o, 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(bytes memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(subject) // Subject length.
            if iszero(gt(l, end)) { end := l }
            if iszero(gt(l, start)) { start := l }
            if lt(start, end) {
                result := mload(0x40)
                let n := sub(end, start)
                let i := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let j := and(add(n, 0x1f), w) } 1 {} {
                    mstore(add(result, j), mload(add(i, j)))
                    j := add(j, w) // `sub(j, 0x20)`.
                    if iszero(j) { break }
                }
                let o := add(add(result, 0x20), n)
                mstore(o, 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, n) // Store the length.
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
    /// `start` is a byte offset.
    function slice(bytes memory subject, uint256 start)
        internal
        pure
        returns (bytes memory result)
    {
        result = slice(subject, start, type(uint256).max);
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
    function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
            start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
            result.offset := add(subject.offset, start)
            result.length := mul(lt(start, end), sub(end, start))
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
    /// `start` is a byte offset. Faster than Solidity's native slicing.
    function sliceCalldata(bytes calldata subject, uint256 start)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
            result.offset := add(subject.offset, start)
            result.length := mul(lt(start, subject.length), sub(subject.length, start))
        }
    }

    /// @dev Reduces the size of `subject` to `n`.
    /// If `n` is greater than the size of `subject`, this will be a no-op.
    function truncate(bytes memory subject, uint256 n)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := subject
            mstore(mul(lt(n, mload(result)), result), n)
        }
    }

    /// @dev Returns a copy of `subject`, with the length reduced to `n`.
    /// If `n` is greater than the size of `subject`, this will be a no-op.
    function truncatedCalldata(bytes calldata subject, uint256 n)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result.offset := subject.offset
            result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
        }
    }

    /// @dev Returns all the indices of `needle` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLen := mload(needle)
            if iszero(gt(searchLen, mload(subject))) {
                result := mload(0x40)
                let i := add(subject, 0x20)
                let o := add(result, 0x20)
                let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, searchLen), h)) {
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
                        o := add(o, 0x20)
                        i := add(i, searchLen) // Advance `i` by `searchLen`.
                        if searchLen {
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
                mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(o, 0x20))
            }
        }
    }

    /// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes.
    function split(bytes memory subject, bytes memory delimiter)
        internal
        pure
        returns (bytes[] memory result)
    {
        uint256[] memory indices = indicesOf(subject, delimiter);
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(add(indicesEnd, w), mload(subject))
            mstore(indices, add(mload(indices), 1))
            for { let prevIndex := 0 } 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let l := sub(index, prevIndex)
                    mstore(element, l) // Store the length of the element.
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(l, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
                    // Allocate memory for the length and the bytes, rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(l, 0x3f), w)))
                    mstore(indexPtr, element) // Store the `element` into the array.
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated bytes of `a` and `b`.
    /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
    function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let w := not(0x1f)
            let aLen := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLen, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLen := mload(b)
            let output := add(result, aLen)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLen, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLen := add(aLen, bLen)
            let last := add(add(result, 0x20), totalLen)
            mstore(last, 0) // Zeroize the slot after the bytes.
            mstore(result, totalLen) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate memory.
        }
    }

    /// @dev Returns whether `a` equals `b`.
    function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
        }
    }

    /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
    function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // These should be evaluated on compile time, as far as possible.
            let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
            let x := not(or(m, or(b, add(m, and(b, m)))))
            let r := shl(7, iszero(iszero(shr(128, x))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
        }
    }

    /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
    /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
    function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLen := mload(a)
            let bLen := mload(b)
            let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
            if n {
                for { let i := 0x20 } 1 {} {
                    let x := mload(add(a, i))
                    let y := mload(add(b, i))
                    if iszero(or(xor(x, y), eq(i, n))) {
                        i := add(i, 0x20)
                        continue
                    }
                    result := sub(gt(x, y), lt(x, y))
                    break
                }
            }
            // forgefmt: disable-next-item
            if iszero(result) {
                let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
                let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
                let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
                result := sub(gt(x, y), lt(x, y))
                if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
            }
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(bytes memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // Assumes that the bytes does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retUnpaddedSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the bytes is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retUnpaddedSize), 0)
            mstore(retStart, 0x20) // Store the return offset.
            // End the transaction, returning the bytes.
            return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
        }
    }

    /// @dev Directly returns `a` with minimal copying.
    function directReturn(bytes[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a) // `a.length`.
            let o := add(a, 0x20) // Start of elements in `a`.
            let u := a // Highest memory slot.
            let w := not(0x1f)
            for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
                let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
                let s := mload(c) // `a[i]`.
                let l := mload(s) // `a[i].length`.
                let r := and(l, 0x1f) // `a[i].length % 32`.
                let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
                // If `s` comes before `o`, or `s` is not zero right padded.
                if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
                    let m := mload(0x40)
                    mstore(m, l) // Copy `a[i].length`.
                    for {} 1 {} {
                        mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
                        z := add(z, w) // `sub(z, 0x20)`.
                        if iszero(z) { break }
                    }
                    let e := add(add(m, 0x20), l)
                    mstore(e, 0) // Zeroize the slot after the copied bytes.
                    mstore(0x40, add(e, 0x20)) // Allocate memory.
                    s := m
                }
                mstore(c, sub(s, o)) // Convert to calldata offset.
                let t := add(l, add(s, 0x20))
                if iszero(lt(t, u)) { u := t }
            }
            let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
            mstore(retStart, 0x20) // Store the return offset.
            return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
        }
    }

    /// @dev Returns the word at `offset`, without any bounds checks.
    /// To load an address, you can use `address(bytes20(load(a, offset)))`.
    function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(add(add(a, 0x20), offset))
        }
    }

    /// @dev Returns the word at `offset`, without any bounds checks.
    /// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`.
    function loadCalldata(bytes calldata a, uint256 offset)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := calldataload(add(a.offset, offset))
        }
    }

    /// @dev Returns empty calldata bytes. For silencing the compiler.
    function emptyCalldata() internal pure returns (bytes calldata result) {
        /// @solidity memory-safe-assembly
        assembly {
            result.length := 0
        }
    }
}

Settings
{
  "remappings": [
    "webauthn-sol/=lib/webauthn-sol/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/",
    "account-abstraction/=lib/account-abstraction/contracts/",
    "ds-test/=lib/webauthn-sol/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"AllowanceExceeded","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"CallFailed","type":"error"},{"inputs":[],"name":"CannotRegisterRootKey","type":"error"},{"inputs":[],"name":"CannotUpdateRootKey","type":"error"},{"inputs":[],"name":"ExcessiveInvalidation","type":"error"},{"inputs":[],"name":"FnSelectorNotRecognized","type":"error"},{"inputs":[],"name":"IncorrectSender","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidHookResponse","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"KeyDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"KeyExpired","type":"error"},{"inputs":[],"name":"NotEntryPoint","type":"error"},{"inputs":[],"name":"OnlyAdminCanSelfCall","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"TransferNativeFailed","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsupportedExecutionMode","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ApproveNative","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ApproveNativeTransient","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newEntryPoint","type":"address"}],"name":"EntryPointUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"indexed":false,"internalType":"Settings","name":"settings","type":"uint256"}],"name":"KeySettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"NativeAllowanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"components":[{"internalType":"enum KeyType","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"publicKey","type":"bytes"}],"indexed":false,"internalType":"struct Key","name":"key","type":"tuple"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferFromNative","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferFromNativeTransient","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"CUSTOM_STORAGE_ROOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENTRY_POINT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveNative","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveNativeTransient","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"},{"internalType":"bool","name":"revertOnFailure","type":"bool"}],"internalType":"struct BatchedCall","name":"batchedCall","type":"tuple"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"},{"internalType":"bool","name":"revertOnFailure","type":"bool"}],"internalType":"struct BatchedCall","name":"batchedCall","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct SignedBatchedCall","name":"signedBatchedCall","type":"tuple"},{"internalType":"bytes","name":"wrappedSignature","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mode","type":"bytes32"},{"internalType":"bytes","name":"executionData","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","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":"","type":"bytes32"}],"name":"executeUserOp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"getKey","outputs":[{"components":[{"internalType":"enum KeyType","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"publicKey","type":"bytes"}],"internalType":"struct Key","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"getKeySettings","outputs":[{"internalType":"Settings","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"key","type":"uint256"}],"name":"getSeq","outputs":[{"internalType":"uint256","name":"seq","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newNonce","type":"uint256"}],"name":"invalidateNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"bytes","name":"wrappedSignature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"keyAt","outputs":[{"components":[{"internalType":"enum KeyType","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"publicKey","type":"bytes"}],"internalType":"struct Key","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyHashes","outputs":[{"internalType":"uint256","name":"_spacer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"namespaceAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"nativeAllowance","outputs":[{"internalType":"uint256","name":"allowance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"key","type":"uint256"}],"name":"nonceSequenceNumber","outputs":[{"internalType":"uint256","name":"seq","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum KeyType","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"publicKey","type":"bytes"}],"internalType":"struct Key","name":"key","type":"tuple"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mode","type":"bytes32"}],"name":"supportsExecutionMode","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFromNative","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFromNativeTransient","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"transientNativeAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"internalType":"Settings","name":"settings","type":"uint256"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"entryPoint","type":"address"}],"name":"updateEntryPoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"prefix","type":"uint96"}],"name":"updateSalt","outputs":[],"stateMutability":"nonpayable","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"},{"internalType":"uint256","name":"missingAccountFunds","type":"uint256"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e0604052346100ce57604080519081016001600160401b038111828210176100ba576040908152600782526621b0b634b13ab960c91b6020830190815281519182016001600160401b038111838210176100ba57604052600582526020820192640312e302e360dc1b845251902060805251902060a0523060c052604051615fb890816100d382396080518181816120dc0152612811015260a0518181816121020152612837015260c05181818161250101526127c30152f35b634e487b7160e01b5f52604160045260245ffd5b5f80fdfe60806040526004361015610015575b3661288157005b5f3560e01c80630f3ebf6e1461024457806312aaac701461023f5780631626ba7e1461023a57806319822f7c146102355780631b71bb6e14610230578063219a260d1461022b57806323d578861461022657806325e5c2431461022157806327258b221461021c57806328495877146102175780632abbf4691461021257806330b1fa3b1461020d5780634223b5c2146102085780636575f6aa146102035780636750aa5f146101fe5780636a1ea88d146101f95780637613e7ba146101f4578063786902f2146101ef578063789ff701146101ea57806384b0196e146101e55780638dd7712f146101e057806394430fa5146101db57806399e1d016146101d6578063a58bb84a146101d1578063ac9650d8146101cc578063b70e36f0146101c7578063b75c7dc6146101c2578063b923614f146101bd578063bf7c5be9146101b8578063c3c16ee4146101b3578063d03c7914146101ae578063e41dae2f146101a9578063e9ae5c53146101a4578063f698da251461019f5763fac750e00361000e5761196a565b611950565b6118a5565b61183d565b61181f565b611678565b611635565b6115f9565b6113fd565b611278565b611174565b61101c565b610fe8565b610e46565b610d9e565b610cc8565b610caf565b610c96565b610c30565b610bcd565b610b9e565b610b34565b610a8e565b610a0e565b610817565b6107b8565b610790565b61070e565b61066a565b610621565b610554565b6103e5565b610393565b610302565b3461026a57602060031936011261026a576020610262600435611984565b604051908152f35b5f80fd5b6003111561027857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9060038210156102785752565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b606060206102ff938184526102ef82850182516102a5565b01519160408082015201906102b2565b90565b3461026a57602060031936011261026a5761032d610321600435611b23565b604051918291826102d7565b0390f35b9181601f8401121561026a5782359167ffffffffffffffff831161026a576020838186019501011161026a57565b90604060031983011261026a57600435916024359067ffffffffffffffff821161026a5761038f91600401610331565b9091565b3461026a5760206103ac6103a63661035f565b91611c5f565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b908161012091031261026a5790565b3461026a57606060031936011261026a5760043567ffffffffffffffff811161026a576104169036906004016103d6565b60443560243573ffffffffffffffffffffffffffffffffffffffff61043961253c565b1633036105015761032d926104836104d792846104d0956104f1575b5061046d610467610100850185611df0565b90612b26565b9693928561047e8598949398611b23565b6129e9565b9461048d82611984565b95156104e75778ffffffffff000000000000000000000000000000000000000086169788955b73ffffffffffffffffffffffffffffffffffffffff9236916109bd565b951661316d565b6040519081529081906020820190565b60019788956104b3565b5f9081803892335af1505f610455565b7fd663742a000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff81160361026a57565b359061055282610529565b565b3461026a57602060031936011261026a5760043561057181610529565b3033036105f95773ffffffffffffffffffffffffffffffffffffffff167f800000000000000000000000000000000000000000000000000000000000000081177f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600557fea942933e7fb7cb728727281a81e352a20dda96dbc4ee97633a3fa25da48e4ab5f80a2005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576004355f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368604602052602060405f2054604051908152f35b3461026a57604060031936011261026a5760043561068781610529565b602435903033036105f95773ffffffffffffffffffffffffffffffffffffffff1690815f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686056020528060405f20556040519081527f30346eac03b1c5913bb026e6d8d0f42783a0c706bb2a86916410dc385cc2723660203092a360405160018152602090f35b3461026a57604060031936011261026a5760043561072b81610529565b602435903033036105f957806107568373ffffffffffffffffffffffffffffffffffffffff9361325c565b60405192835216907ff8c1385bb618a432aebbaae5bfab911559154982a64e1750b17b50f5782dc98860203092a360405160018152602090f35b3461026a57602060031936011261026a5760206107ae60043561327b565b6040519015158152f35b3461026a575f60031936011261026a5761032d6040516107d9604082610956565b601581527f556e69737761702e43616c696275722e312e302e30000000000000000000000060208201526040519182916020835260208301906102b2565b3461026a57602060031936011261026a576004356bffffffffffffffffffffffff811680910361026a573033036105f9577f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606546bffffffffffffffffffffffff8116820361088157005b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016177f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606557f0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d315f80a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761093557604052565b6108ec565b6060810190811067ffffffffffffffff82111761093557604052565b90601f601f19910116810190811067ffffffffffffffff82111761093557604052565b6040519061055260c083610956565b60405190610552606083610956565b6003111561026a57565b67ffffffffffffffff811161093557601f01601f191660200190565b9291926109c9826109a1565b916109d76040519384610956565b82948184528183011161026a578281602093845f960137010152565b9080601f8301121561026a578160206102ff933591016109bd565b3461026a57602060031936011261026a5760043567ffffffffffffffff811161026a576040600319823603011261026a57604051610a4b81610919565b8160040135610a5981610997565b8152602482013567ffffffffffffffff811161026a57610a8c926004610a8292369201016109f3565b6020820152611e55565b005b3461026a57602060031936011261026a57600435610aaa611a0c565b5080610ae16318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090565b015490610aec61375e565b1115610b0c576103218168fbb67fda52d4bfb8bf61032d93141502611b23565b7f4e23d035000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576020610262600435610b55612765565b604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b9060206102ff9281815201906102b2565b3461026a575f60031936011261026a5761032d610bb96120b1565b6040519182916020835260208301906102b2565b3461026a57602060031936011261026a5777ffffffffffffffffffffffffffffffffffffffffffffffff600435165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368604602052602060405f2054604051908152f35b3461026a575f60031936011261026a5760206040517f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686008152f35b600319606091011261026a57600435610c8281610529565b90602435610c8f81610529565b9060443590565b3461026a5760206107ae610ca936610c6a565b91612145565b3461026a5760206107ae610cc236610c6a565b91612277565b3461026a575f60031936011261026a577fff00000000000000000000000000000000000000000000000000000000000000610d4f73ffffffffffffffffffffffffffffffffffffffff610d41610d1c612408565b97946040999397919699949294519a8b9a168a5260e060208b015260e08a01906102b2565b9088820360408a01526102b2565b93606087015216608085015260a084015282810360c0840152602080835192838152019201905f5b818110610d85575050500390f35b8251845285945060209384019390920191600101610d77565b3461026a57604060031936011261026a5760043567ffffffffffffffff811161026a57610dcf9036906004016103d6565b73ffffffffffffffffffffffffffffffffffffffff610dec61253c565b16330361050157610e16610e07610467610100840184611df0565b50505050916060810190611df0565b60048193929310610e3957826004610e3492610a8c95019101610fc2565b613489565b633b99b53d5f526004601cfd5b3461026a575f60031936011261026a576020610e6061253c565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b67ffffffffffffffff81116109355760051b60200190565b9080601f8301121561026a57813591610eae83610e7e565b92610ebc6040519485610956565b80845260208085019160051b8301019183831161026a5760208101915b838310610ee857505050505090565b823567ffffffffffffffff811161026a578201906060601f19838803011261026a5760405190610f178261093a565b6020830135610f2581610529565b82526040830135602083015260608301359167ffffffffffffffff831161026a57610f58886020809695819601016109f3565b6040820152815201920191610ed9565b8015150361026a57565b91909160408184031261026a5760405190610f8c82610919565b819381359167ffffffffffffffff831161026a57610fb06020939284938301610e96565b8452013591610fbe83610f68565b0152565b9060208282031261026a57813567ffffffffffffffff811161026a576102ff9201610f72565b602060031936011261026a5760043567ffffffffffffffff811161026a57611017610a8c913690600401610f72565b6125b8565b3461026a57604060031936011261026a576004356024353033036105f95781156110cf576110498261327b565b156110a75760207f55194732cd17a56216773dcef66731844f1900f9b878633e3be2b6cce1e542c991835f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860382528060405f2055604051908152a2005b7fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fb37b2fa0000000000000000000000000000000000000000000000000000000005f5260045ffd5b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061112957505050505090565b9091929394602080611165837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0866001960301875289516102b2565b9701930193019193929061111a565b602060031936011261026a5760043567ffffffffffffffff811161026a573660238201121561026a5780600401359067ffffffffffffffff821161026a576024810190602436918460051b01011161026a576111cf82610e7e565b916111dd6040519384610956565b808352601f196111ec82610e7e565b015f5b8181106112675750505f5b81811061120f576040518061032d86826110f7565b5f8061121c838587612605565b9061122c60405180938193612621565b0390305af461123961262e565b901561125f579060019161124d828761265d565b52611258818661265d565b50016111fa565b602081519101fd5b8060606020809388010152016111ef565b3461026a57602060031936011261026a576004353033036105f9578060401c6112f36112e58277ffffffffffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f2090565b5467ffffffffffffffff1690565b9167ffffffffffffffff81169267ffffffffffffffff81168411156113d55767ffffffffffffffff61ffff91850316116113ad577f4d9dbebf1d909894d9c26fe228c27cec643b2cb490124e5b658f4edd203c20c1926113976113a89377ffffffffffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f2090565b556040519081529081906020820190565b0390a1005b7f24d35a26000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f756688fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576004353033036105f957805f906114506318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090565b9068fbb67fda52d4bfb8bf84146115ec5783156115dc575b811980549182159260011c5f19810191600183811b179461157057856020525f5260405f20948554928315611561575f97505f19840103611543575b50505055556114b360015b1590565b6110a7576114f06114eb825f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f2090565b6126d3565b5f8181527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205260408120557fe5af7daed5ab2a2dc5f98d53619f05089c0c14d11a6621f6b906a2366c9a7ab35f80a2005b5f1980849383010154928392010155855260408520555f80806114a4565b505050505050506114b3901590565b955050505050600190828154146115c057818101838154146115ac5750600201918254146115a25750600190506114b3565b5f6114b392551590565b6114b3935060025f92019081549055551590565b6114b39250806002835f93019182548155019081549055551590565b5068fbb67fda52d4bfb8bf611468565b63f5a267f15f526004601cfd5b3461026a575f60031936011261026a5760207f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860154604051908152f35b3461026a57602060031936011261026a5773ffffffffffffffffffffffffffffffffffffffff60043561166781610529565b165f526020805f205c604051908152f35b604060031936011261026a5760043567ffffffffffffffff811161026a57806004019060a0600319823603011261026a5760243567ffffffffffffffff811161026a576116c9903690600401610331565b91909273ffffffffffffffffffffffffffffffffffffffff60648301356116ef81610529565b168015908115611815575b50156105f9576084820135801515908161180b575b506117e3576117316114af936117619561172c6024860135613e8f565b613ee0565b9691604461175361174e61174999949699368961368a565b613f20565b6120a5565b960135968661047e89611b23565b6117bb57610a8c94610e34938573ffffffffffffffffffffffffffffffffffffffff6117a46117ab9561179384611984565b9561179d87612dc2565b36916109bd565b93166140d1565b6117b6369180612732565b610f72565b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f0819bdcd000000000000000000000000000000000000000000000000000000005f5260045ffd5b905042115f61170f565b905033145f6116fa565b3461026a57602060031936011261026a5760206107ae600435613709565b3461026a57602060031936011261026a5773ffffffffffffffffffffffffffffffffffffffff60043561186f81610529565b165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368605602052602060405f2054604051908152f35b6118ae3661035f565b6118b9839293613709565b156119285782019160208184031261026a5780359067ffffffffffffffff821161026a57610a8c937eff0000000000000000000000000000000000000000000000000000000000009261190c9201610e96565b916040519261191a84610919565b8352161560208201526125b8565b7f7f181275000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a575f60031936011261026a576020610262612765565b3461026a575f60031936011261026a57602061026261375e565b80156119ed576119938161327b565b6119bf577fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205260405f205490565b5079010000000000000000000000000000000000000000000000000090565b60405190611a1982610919565b60606020835f81520152565b90600182811c92168015611a6c575b6020831014611a3f57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611a34565b81601f8201121561026a57805190611a8d826109a1565b92611a9b6040519485610956565b8284526020838301011161026a57815f9260208093018386015e8301015290565b60208183031261026a5780519067ffffffffffffffff821161026a570160408183031261026a5760405191611af083610919565b8151611afb81610997565b8352602082015167ffffffffffffffff811161026a57611b1b9201611a76565b602082015290565b611b2b611a0c565b508015611c5657611b3b8161327b565b611b67577fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f206040515f825492611ba184611a25565b9081845260208401946001811690815f14611c1b5750600114611bde575b505081611bd46102ff94936020930382610956565b8051010190611abc565b5f908152602081209092505b818310611c01575050810160200181611bd4611bbf565b600181602092949394548385880101520191019190611bea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686525050151560051b8201602001905081611bd4611bbf565b506102ff6128b7565b9180611d7e5761773961ffff821904028314611d5757611c7e91612b26565b9391611c8d8396949296611b23565b91611ca28282611c9b6120b1565b8887612b79565b928315611d3b575b50505015611d1357611ce9611cef94611cc283611984565b611ccb81612dc2565b73ffffffffffffffffffffffffffffffffffffffff169436916109bd565b92612e6e565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b505050507fffffffff0000000000000000000000000000000000000000000000000000000090565b611d4f935085611d49612765565b91612d60565b5f8080611caa565b5050507f773900010000000000000000000000000000000000000000000000000000000090565b90611d8982826128f1565b611d975790611c7e91612b26565b611da39261047e6128b7565b15611dcc577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b7fffffffff0000000000000000000000000000000000000000000000000000000090565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026a570180359067ffffffffffffffff821161026a5760200191813603831361026a57565b60405190611e50602083610956565b5f8252565b3033036105f957805160038110156102785780611e7360029261026e565b1480611f4a575b611f22577f8df00f8e3bbfb2c3024a60b74e1d4e520f7cbe1da3476726241146ecf6328832611f1d611eab83613318565b92611f07604051611ed181611ec385602083016102d7565b03601f198101835282610956565b611f02865f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f2090565b611fda565b611f1084613355565b50604051918291826102d7565b0390a2565b7f41e2e8f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b50602081015173ffffffffffffffffffffffffffffffffffffffff611f7a825192602080309583010191016129d4565b1614611e7a565b818110611f8c575050565b5f8155600101611f81565b9190601f8111611fa657505050565b610552925f5260205f20906020601f840160051c83019310611fd0575b601f0160051c0190611f81565b9091508190611fc3565b919091825167ffffffffffffffff81116109355761200281611ffc8454611a25565b84611f97565b6020601f82116001146120405781906120319394955f92612035575b50505f198260011b9260031b1c19161790565b9055565b015190505f8061201e565b601f19821690612053845f5260205f2090565b915f5b81811061208d57509583600195969710612075575b505050811b019055565b01515f1960f88460031b161c191690555f808061206b565b9192602060018192868b015181550194019201612056565b6102ff90610b55612765565b73ffffffffffffffffffffffffffffffffffffffff6120ce612408565b5094509150939150604051937f000000000000000000000000000000000000000000000000000000000000000060208601527f00000000000000000000000000000000000000000000000000000000000000006040860152606085015216608083015260a082015260a081526102ff60c082610956565b821561226f5773ffffffffffffffffffffffffffffffffffffffff3091160361224757335f908152602090205c9082821061221f5781835f1973ffffffffffffffffffffffffffffffffffffffff941061220d575b505016905f80808084865af16121ae61262e565b50156121e5576040519081527f3f1beca043a9fe9118bbaeca0035e81e02d6d7cf184bf32fa9dfbd73fdd027c060203092a3600190565b7fb06a467a000000000000000000000000000000000000000000000000000000005f5260045ffd5b61221891033361325c565b5f8361219a565b7fc45cb513000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7d1c29f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b505050600190565b91905f9282156123ff5773ffffffffffffffffffffffffffffffffffffffff3091160361224757335f9081527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368605602052604090205482811061221f575f198110612364575b5073ffffffffffffffffffffffffffffffffffffffff16918080808085875af161230461262e565b501561233c57506040519081527fed1cf8378e55f85e35be72eebdbef1b7347825916e51aa538d1855113f8c259d60203092a3600190565b807fb06a467a0000000000000000000000000000000000000000000000000000000060049252fd5b73ffffffffffffffffffffffffffffffffffffffff919350829003925f93806123ca3373ffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860560205260405f2090565b5560405190815233907f85b16643b7d42712d1470a1ed9822d6e8cadad23eb1141cabefa28da0944c5b790602090a2906122dc565b50505050600190565b7f1f000000000000000000000000000000000000000000000000000000000000009060408051906124398183610956565b600782527f43616c69627572000000000000000000000000000000000000000000000000006020830152805161246f8282610956565b600581527f312e302e3000000000000000000000000000000000000000000000000000000060208201527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606549293909246923092909160a01b7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001617915161252f602082610956565b5f80825236602083013790565b7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600547f800000000000000000000000000000000000000000000000000000000000000081161561259f5773ffffffffffffffffffffffffffffffffffffffff1690565b50734337084d9e255ff0702461cf8895ce9e3b5ff10890565b6125c1336135df565b6125ca81613638565b156105f95761055291613489565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9082101561261c5761038f9160051b810190611df0565b6125d8565b908092918237015f815290565b3d15612658573d9061263f826109a1565b9161264d6040519384610956565b82523d5f602084013e565b606090565b805182101561261c5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908160021b917f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116036126ce57565b612671565b6126dd8154611a25565b90816126e7575050565b81601f5f93116001146126f8575055565b8183526020832061271491601f0160051c810190600101611f81565b808252602082209081548360011b905f198560031b1c191617905555565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561026a570190565b7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686065460a01b7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161760405160208101917fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647283527f000000000000000000000000000000000000000000000000000000000000000060408301527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a083015260c082015260c0815261287b60e082610956565b51902090565b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214176128ae57633c10b94e5f526004601cfd5b6020526020603cf35b6128bf611a0c565b50604051306020820152602081526128d8604082610956565b604051906128e582610919565b60028252602082015290565b5060418114908115612901575090565b604091501490565b919082604091031261026a576020825192015190565b60208183031261026a5780359067ffffffffffffffff821161026a57019060c08282031261026a5761294f610979565b91803567ffffffffffffffff811161026a578261296d9183016109f3565b8352602081013567ffffffffffffffff811161026a5760a0926129919183016109f3565b6020840152604081013560408401526060810135606084015260808101356080840152013560a082015290565b919082604091031261026a576020823592013590565b9081602091031261026a57516102ff81610529565b9290600284516129f88161026e565b612a018161026e565b03612a6a579073ffffffffffffffffffffffffffffffffffffffff92612a2692613b2f565b169081612a335750505f90565b612a4d6020612a66920151602080825183010191016129d4565b73ffffffffffffffffffffffffffffffffffffffff1690565b1490565b8351612a758161026e565b612a7e8161026e565b612abb57612ab690612aae612aa360206102ff97015160208082518301019101612909565b9590948101906129be565b929091613aec565b613b04565b60018451612ac88161026e565b612ad18161026e565b03612b1e57611ec3612b19612b04612af960206102ff98015160208082518301019101612909565b96909581019061291f565b92604051928391602083019190602083019252565b6138de565b505050505f90565b9190823592612b358282613bbd565b9093819363ffffffff60408501351684019063ffffffff82351694602080840193870101910110610e3957604090939210612b6c57565b634be6321b5f526004601cfd5b9091939293612b888486614660565b949093612b9f602088013592604089013598614690565b9091612bde8985604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b03612d5457612bec91613c80565b82959299939199158015612d4c575b612d3e57611ec3612cd9612c266102ff9c612c1e612cfc96612d389b36916109bd565b9436916109bd565b604051928391605c612c6360208501977f5479706564446174615369676e280000000000000000000000000000000000008952602e860190613809565b7f20636f6e74656e74732c737472696e67206e616d652c737472696e672076657281527f73696f6e2c75696e7432353620636861696e49642c616464726573732076657260208201527f696679696e67436f6e74726163742c627974657333322073616c74290000000060408201520190613809565b51902092611ec36040519384926020840196875260408401526060830190613809565b51902090604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b906129e9565b505050505050505050505f90565b508015612bfb565b50505050505050505f90565b906102ff949392612d3891604090601c60208351612d7e8582610956565b828152017f506572736f6e616c5369676e28627974657320707265666978656429000000008152209180519160208301938452818301528152612cfc606082610956565b612dcb90613e70565b90612dd35750565b64ffffffffff907f48c76fe1000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b51907fffffffff000000000000000000000000000000000000000000000000000000008216820361026a57565b9081602091031261026a576102ff90612e06565b6102ff93926060928252602082015281604082015201906102b2565b6040513d5f823e3d90fd5b9290919260048116612e81575b50505050565b612ed39373ffffffffffffffffffffffffffffffffffffffff602094604051968795869485937f9ac4eafd00000000000000000000000000000000000000000000000000000000855260048501612e47565b0392165afa908115612f91577f9ac4eafd00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91612f62575b501603612f3a575f808080612e7b565b7f1e048e1d000000000000000000000000000000000000000000000000000000005f5260045ffd5b612f84915060203d602011612f8a575b612f7c8183610956565b810190612e33565b5f612f2a565b503d612f72565b612e63565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026a57016020813591019167ffffffffffffffff821161026a57813603831361026a57565b601f8260209493601f1993818652868601375f8582860101520116010190565b91613155906102ff96949592845260a0602085015261304560a0850161302b83610547565b73ffffffffffffffffffffffffffffffffffffffff169052565b602081013560c08501526131246131186130b961307b6130686040860186612f96565b61012060e08b01526101c08a0191612fe6565b6130886060860186612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608a8403016101008b0152612fe6565b608084013561012088015260a084013561014088015260c08401356101608801526130e760e0850185612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60898403016101808a0152612fe6565b91610100810190612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60868403016101a0870152612fe6565b936040830152606082015260808184039101526102b2565b9190939460028316613182575b505050505050565b6020946131d473ffffffffffffffffffffffffffffffffffffffff92604051988997889687957f9e364dba00000000000000000000000000000000000000000000000000000000875260048701613006565b0392165afa908115612f91577f9e364dba00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f9161323d575b501603612f3a575f808080808061317a565b613256915060203d602011612f8a57612f7c8183610956565b5f61322b565b73ffffffffffffffffffffffffffffffffffffffff165f5260205f205d565b6132b07f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686016318fb58646004525f5260245f2090565b68fbb67fda52d4bfb8bf82146115ec578115613307575b801954156132de576020525f5260405f2054151590565b9060019181815414613302578183820154146133025760020154146102ff57505f90565b505090565b68fbb67fda52d4bfb8bf91506132c7565b8051906003821015610278576020015160208151910120604051906133416020830180946102a5565b60408201526040815261287b606082610956565b905f9161338d7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686016318fb58646004525f5260245f2090565b9068fbb67fda52d4bfb8bf81146115ec578015613479575b8119918254918160205282156133ed575b805f5260405f20928354156133cc575050505050565b9091929394955060011c8092015560010180915560011b6001179055600190565b91508054801561347057828114612e7b57600182018054908115613462575083811461345b576002830191825492831561344c575084831461317a575f52600160405f20555f52600260405f20555f52600360405f20556007916133b6565b95505050505091925055600190565b5050505050565b945050505091925055600190565b50555060019150565b5068fbb67fda52d4bfb8bf6133a5565b5f5b81518051821015612e7b57816134a09161265d565b51805173ffffffffffffffffffffffffffffffffffffffff16806135d9575030905b6134cb85611984565b60ff60c882901c1615806135ba575b6135925785925f8073ffffffffffffffffffffffffffffffffffffffff613537941694602081019361351760408651930192835190838b8b6147d9565b9451915191602083519301915af1928361352f61262e565b958692614966565b1580613585575b61354b575060010161348b565b613581906040519182917fa5fa8d2b00000000000000000000000000000000000000000000000000000000835260048301610b8d565b0390fd5b506020830151151561353e565b7f3ceb88d9000000000000000000000000000000000000000000000000000000005f5260045ffd5b503073ffffffffffffffffffffffffffffffffffffffff8416146134da565b906134c2565b73ffffffffffffffffffffffffffffffffffffffff16308114613633576102ff9060405190602082015260208152613618604082610956565b6040519061362582610919565b600282526020820152613318565b505f90565b8015613684576136478161327b565b15613633575f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205261367f60405f2054613e70565b501590565b50600190565b91909160a08184031261026a576040519060a0820182811067ffffffffffffffff82111761093557604052819381359167ffffffffffffffff831161026a576136d96080939284938301610f72565b8452602081013560208501526040810135604085015260608101356136fd81610529565b60608501520135910152565b7f01000000000000000000000000000000000000000000000000000000000000008114908115613737575090565b7f010100000000000000000000000000000000000000000000000000000000000091501490565b6318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090811954918260011c9215159080541560026001830154159201541592156137b457505050565b90919293505f906137da57506001906137d557506002906102ff5750600390565b919050565b92915050565b90601582018092116126ce57565b90600282018092116126ce57565b919082018092116126ce57565b805191908290602001825e015f815290565b90610552600161385b936040519485917f226368616c6c656e6765223a22000000000000000000000000000000000000006020840152602d830190613809565b7f22000000000000000000000000000000000000000000000000000000000000008152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1810185520183610956565b80516020101561261c5760400190565b6138c89060209392613809565b9081520190565b9081602091031261026a575190565b92919060a081019384517f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a810613ad95760208201907fff1a2a9176d650e4a99dedb58f1793003935130579fe17b5a3f698ac5b00e63461394d83516060860151613947816137e0565b91614c42565b6020815191012003613ae25761396561396a9161419b565b61381b565b61397f825160408501516139478451826137fc565b60208151910120906020815191012003613ad9577f0100000000000000000000000000000000000000000000000000000000000000806139e86139c285516138ab565b517fff000000000000000000000000000000000000000000000000000000000000001690565b1603613ad9575f613a026020925160405191828092613809565b039060025afa15612f915760205f613a378151613a2b8551611ec36040519384928884016138bb565b60405191828092613809565b039060025afa15612f915760805f519101935f80865185613a888551611ec38a60405194859360208501978c899192608093969594919660a084019784526020840152604083015260608201520152565b51906101005afa94613a9861262e565b80519680613ad0575b613ab457506102ff955051905191614202565b600196612a6696508101602090810195500192506138cf915050565b50861515613aa1565b50505050505f90565b5050505050505f90565b5f5260206001815f60025afa51903d15613b0257565bfe5b93929190613b15848484848961435c565b90959015613b2557505050505090565b6102ff9550614417565b604080515f95949093918114613b7a57604114613b4b57505050565b604080929395508101355f1a60205281375b5f526020604060805f60015afa505f6060523d6060185191604052565b507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91929450602081013590601b8260ff1c016020523560405216606052613b5d565b909163ffffffff60208301351682019263ffffffff84351692602080860195850101910110610e3957565b905f1982019182116126ce57565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255103907fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255182116126ce57565b9082101561261c570190565b80156126ce575f190190565b90929192831161026a579190565b9093929384831161026a57841161026a578101920390565b9080613c93575b50505f905f905f905f90565b7f29000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000613d11613ceb613ce485613be8565b8587613c42565b357fff000000000000000000000000000000000000000000000000000000000000001690565b1603613db7575f5b818110613d2c575b5050505b5f80613c87565b613d3a613ceb828486613c42565b7fff0000000000000000000000000000000000000000000000000000000000000081167f280000000000000000000000000000000000000000000000000000000000000003613da257508015613d9d57613d95908284613c5a565b939093929190565b613d21565b613dab906146bb565b613d9d57600101613d19565b9081805b613dc8575b505050613d25565b613de2613ceb613ddb8396949596613be8565b8686613c42565b7fff0000000000000000000000000000000000000000000000000000000000000081167f290000000000000000000000000000000000000000000000000000000000000003613e4b575080613e3c85613e44938187613c68565b959094613c5a565b9293929091565b613e5890949392946146bb565b613e6b57613e6590613c4e565b80613dbb565b613dc0565b60a01c64ffffffffff16908115613e88574282109190565b5f91508190565b8060401c5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f208054915f1983146126ce5767ffffffffffffffff9160018401905516036113d557565b909163ffffffff82351682019063ffffffff8235169060208084019383010184860110610e3957613f15604093958395613bbd565b9390939210612b6c57565b60c1610100613f326040519182610956565b8181527f290000000000000000000000000000000000000000000000000000000000000060e060208301927f5369676e65644261746368656443616c6c284261746368656443616c6c20626184527f746368656443616c6c2c75696e74323536206e6f6e63652c627974657333322060408201527f6b6579486173682c61646472657373206578656375746f722c75696e7432353660608201527f20646561646c696e65294261746368656443616c6c2843616c6c5b5d2063616c60808201527f6c732c626f6f6c207265766572744f6e4661696c7572652943616c6c2861646460a08201527f7265737320746f2c75696e743235362076616c75652c6279746573206461746160c08201520152209061287b61404f8251614a51565b611ec36020840151936040810151906080614081606083015173ffffffffffffffffffffffffffffffffffffffff1690565b9101519160405196879560208701998a929360a09473ffffffffffffffffffffffffffffffffffffffff93989796929860c086019986526020860152604085015260608401521660808201520152565b92909192600181166140e35750505050565b6141359373ffffffffffffffffffffffffffffffffffffffff602094604051968795869485937f33dd593c00000000000000000000000000000000000000000000000000000000855260048501612e47565b0392165afa908115612f91577f33dd593c00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91612f6257501603612f3a575f808080612e7b565b6040516102ff916141ad606083610956565b604082527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208301527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f6040830152614cec565b93919092938315801561431d575b8015614315575b80156142eb575b613ad95761422c8386614d93565b15613ad95760405191602083526020808401526020604084015260608301527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f60808301527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255160a083015260208260c08160055f19fa1561026a577fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551946142e593866142df945181818909940991614e5f565b91613bf6565b90081590565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255182101561421e565b508115614217565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551841015614210565b9081602091031261026a57516102ff81610f68565b91909361436c6114af83876156fe565b8015614404575b6143f8575f94611ec36143b29287966040519586946020860198899192608093969594919660a084019784526020840152604083015260608201520152565b51906101005afa6143c161262e565b90806143ed575b156143e657806020806143e093518301019101614347565b90600190565b505f905f90565b5060208151146143c8565b50505050505f90600190565b506144126114af8286615775565b614373565b909392919261442684866156fe565b15801561464f575b613ad9577fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255161461c612a669561461161462896614469615804565b95614472610988565b5f81525f60208201525f6040820152875261448b610988565b9182526020820152600160408201526144a48660200190565b9081526144af610988565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29681527f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5602082015260016040820152608087019081526146076145138351615ac2565b604089019081526145f86145e961452a8551615ac2565b6101008c0190815261453f8751855190615aff565b9560608d019687528c61455f6145588a51845190615aff565b9160a00190565b528c6145786145718751845190615aff565b9160c00190565b528c61459161458a8951845190615aff565b9160e00190565b528c6145ab6145a38a51855190615aff565b916101200190565b528c6145c56145bd8751855190615aff565b916101400190565b528c6145df6145d78951855190615aff565b916101600190565b5251905190615aff565b6101808b018181529551615aff565b6101a08a015251835190615aff565b6101c088016145df565b6101e0850152615b1e565b8181880993099061584a565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551900690565b5061465a8184615775565b1561442e565b909163ffffffff82351682019263ffffffff8435169260208086019585010191011061468857565b9150505f5f91565b909163ffffffff60608301351682019263ffffffff8435169260208086019585010191011061468857565b7fff0000000000000000000000000000000000000000000000000000000000000016801590811561477a575b8115614750575b8115614726575b81156146ff575090565b7f290000000000000000000000000000000000000000000000000000000000000091501490565b7f2800000000000000000000000000000000000000000000000000000000000000811491506146f5565b7f2c00000000000000000000000000000000000000000000000000000000000000811491506146ee565b7f2000000000000000000000000000000000000000000000000000000000000000811491506146e7565b91909160408184031261026a576147ba81612e06565b92602082015167ffffffffffffffff811161026a576102ff9201611a76565b6060959490929190600884166147f0575050505050565b5f94965073ffffffffffffffffffffffffffffffffffffffff8094939261486087936040519a8b98899788957fec9b4ee4000000000000000000000000000000000000000000000000000000008752600487015216602485015260448401526080606484015260848301906102b2565b0393165af18015612f91575f925f916148c9575b507fffffffff000000000000000000000000000000000000000000000000000000007fec9b4ee40000000000000000000000000000000000000000000000000000000091931603612f3a575f8080808061345b565b7fffffffff0000000000000000000000000000000000000000000000000000000093507fec9b4ee400000000000000000000000000000000000000000000000000000000915061492a903d805f833e6149228183610956565b8101906147a4565b9390939150614874565b926102ff9492614958928552151560208501526080604085015260808401906102b2565b9160608184039101526102b2565b90929160108216614978575050505050565b5f73ffffffffffffffffffffffffffffffffffffffff6020956149ca604051988997889687947fc82b175900000000000000000000000000000000000000000000000000000000865260048601614934565b0393165af1908115612f91577fc82b175900000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91614a32575b501603612f3a575f8080808061345b565b614a4b915060203d602011612f8a57612f7c8183610956565b5f614a21565b60806057604051614a63608082610956565b8181527f6e743235362076616c75652c6279746573206461746129000000000000000000606060208301927f4261746368656443616c6c2843616c6c5b5d2063616c6c732c626f6f6c20726584527f766572744f6e4661696c7572652943616c6c286164647265737320746f2c75696040820152015220908251805194601f19614b05614aef88610e7e565b97614afd604051998a610956565b808952610e7e565b013660208801376060935f5b8351811015614bee5780614b276001928661265d565b516029604051614b378a82610956565b8181527f7465732064617461290000000000000000000000000000000000000000000000604060208301927f43616c6c286164647265737320746f2c75696e743235362076616c75652c627984520152209073ffffffffffffffffffffffffffffffffffffffff81511690604060208201519101516020815191012090604051926020840194855260408401528a83015288820152878152614bda60a082610956565b519020614be7828b61265d565b5201614b11565b509493509461287b9250614c1f9150602090604051614c1481611ec3858201809561595b565b519020930151151590565b604080516020810195865290810193909352151560608301528160808101611ec3565b805160609493929083811115614cb3575b81811115614cab575b50828110614c6957505050565b6040519450918290039101601f19601f830181165b8083015181870152018015614c9657601f1990614c7e565b505060408184015f6020820152016040528252565b90505f614c5c565b925082614c53565b90614cc5826109a1565b614cd26040519182610956565b828152601f19614ce282946109a1565b0190602036910137565b90815115614d895790614d19614d14614d0d614d08845161269e565b6137ee565b6003900490565b614cbb565b916020830190828051019060208201928351945f85525b838110614d3f57505050505290565b600360049101916001603f845182828260121c16880101518453828282600c1c16880101518385015382828260061c16880101516002850153168501015160038201530190614d30565b50506102ff611e41565b6ffffffffeffffffffffffffffffffffff60601b198110801590614e41575b8015614e30575b614e2a576ffffffffeffffffffffffffffffffffff60601b197f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b818381807fffffffff00000001000000000000000000000000fffffffffffffffffffffffc81970991818180090908089180091490565b50505f90565b5080158015614db957508115614db9565b506ffffffffeffffffffffffffffffffffff60601b19821015614db2565b90915f925f9160ff958115806156f6575b6156eb57614e7e8386615988565b9490978815806156e3575b615695575b83811c60028460fe1c16015b1561567d57600184821c16600284831c60011b160160018114615632575b60028114615625575b60031461561a575b5f1990969493929196019460019889975b875f1911614f715750505050505050505060405191606083015260208252602080830152602060408301527fffffffff00000001000000000000000000000000fffffffffffffffffffffffd60808301526ffffffffeffffffffffffffffffffffff60601b1960a083015260208260c08160055f19fa1561026a576ffffffffeffffffffffffffffffffffff60601b199151900990565b6ffffffffeffffffffffffffffffffffff60601b198160029c989a9c9b959697999b09936ffffffffeffffffffffffffffffffffff60601b1985800980956ffffffffeffffffffffffffffffffffff60601b19828409966ffffffffeffffffffffffffffffffffff60601b199109916ffffffffeffffffffffffffffffffffff60601b198a8208908a6ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b19906003099c6ffffffffeffffffffffffffffffffffff60601b19908309986ffffffffeffffffffffffffffffffffff60601b1991099b6ffffffffeffffffffffffffffffffffff60601b19867fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b19828009906ffffffffeffffffffffffffffffffffff60601b199108956ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199087086ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b1981938309906ffffffffeffffffffffffffffffffffff60601b19910891878c1c600116878d1c60011b6002160180156155f557600181146155aa575b6002811461559f575b600314615596575b8c15615581578c916ffffffffeffffffffffffffffffffffff60601b198085818d819609089388820392090894811561536c575b6ffffffffeffffffffffffffffffffffff60601b19868009986ffffffffeffffffffffffffffffffffff60601b198a9788099d8e976ffffffffeffffffffffffffffffffffff60601b1991099d6ffffffffeffffffffffffffffffffffff60601b199109986ffffffffeffffffffffffffffffffffff60601b199109916ffffffffeffffffffffffffffffffffff60601b19837fffffffff00000001000000000000000000000000fffffffffffffffffffffffd09866ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b19848009906ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b199108956ffffffffeffffffffffffffffffffffff60601b19910991856ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b199109906ffffffffeffffffffffffffffffffffff60601b19910892985f19905b0196949392979597614eda565b8c861561537957506151ce565b989150919a94506ffffffffeffffffffffffffffffffffff60601b198b7fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b198180099283916ffffffffeffffffffffffffffffffffff60601b19838309946ffffffffeffffffffffffffffffffffff60601b1991099d8e916ffffffffeffffffffffffffffffffffff60601b198281038208916ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b1990600309926ffffffffeffffffffffffffffffffffff60601b199109986ffffffffeffffffffffffffffffffffff60601b1991099b6ffffffffeffffffffffffffffffffffff60601b19837fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b19838009906ffffffffeffffffffffffffffffffffff60601b1991089b6ffffffffeffffffffffffffffffffffff60601b199109918b6ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b1991086ffffffffeffffffffffffffffffffffff60601b199109906ffffffffeffffffffffffffffffffffff60601b199108925f199061535f565b60019c50909a8c98509094505f19915061535f565b5050818361519a565b8b92508a9150615192565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29692507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f59150615189565b5050505f19906ffffffffeffffffffffffffffffffffff60601b199a949a039361535f565b889750859150614ec9565b9697508796859250614ec1565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29698507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f59250614eb8565b5f1901600184821c16600284831c60011b1601614e9a565b91927fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551919382039008915f918315806156db575b15614e8e575050505050505050505f90565b5060016156c9565b508515614e89565b505050505050505f90565b508015614e70565b90811515918261574b575b5081615741575b81615719575090565b7f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a89150111590565b8015159150615710565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325511191505f615709565b6ffffffffeffffffffffffffffffffffff60601b1980807f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b8185817fffffffff00000001000000000000000000000000fffffffffffffffffffffffc81838009080908818580091493109110161690565b604051906157f38261093a565b5f6040838281528260208201520152565b604051906102006158158184610956565b825f5b82811061582457505050565b60209061582f6157e6565b8184015201615818565b90601081101561261c5760051b0190565b5f9392849283929183915b6080831061586b575050505061038f9293615db4565b85615939575b600c61587d8260fc1c90565b16600361588a8460fe1c90565b161760406158988287615839565b5101516158c0575b506158b76158b060019260021b90565b9260021b90565b92019190615855565b959194909782155f1461590f575050506158da8483615839565b51519260016158b76158b0604061590060206158f68b8a615839565b5101519988615839565b5101519796995b9250506158a0565b6158b0959260019261592e926159286158b79a89615839565b51615c0b565b979196909699615907565b969461594a91946159509396615b84565b91615b84565b949193909396615871565b80516020909101905f5b8181106159725750505090565b8251845260209384019390920191600101615965565b91907f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2967f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5918015615abc578461038f9495831480615ab3575b15615a9e5750506ffffffffeffffffffffffffffffffffff60601b1982600209916ffffffffeffffffffffffffffffffffff60601b198084800993818080808881818a09950996817fffffffff00000001000000000000000000000000fffffffffffffffffffffffe816001840892080960030981808080867fffffffff00000001000000000000000000000000fffffffffffffffffffffffd0981858009089681600181818c099b099809810393868203900890090890615ed1565b909192615aaa93615e33565b92909190615ed1565b508184146159e1565b50925090565b615ae290615ace6157e6565b508051906040602082015191015191615b84565b9060405192615af08461093a565b83526020830152604082015290565b615ae291615b0b6157e6565b5080516040602083015192015192615c0b565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325517fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f615b6992615f67565b9015615b725790565b634e487b715f5260126020526024601cfd5b9290916ffffffffeffffffffffffffffffffffff60601b1980918180868009968180808a818080808a800980097fffffffff00000001000000000000000000000000fffffffffffffffffffffffc09818088800960030908940960040991818080808087600209810381868009089c80096008098103938b82039008900908940960020990565b91939092935f945f945f946040810151906ffffffffeffffffffffffffffffffffff60601b198280096ffffffffeffffffffffffffffffffffff60601b19858009926ffffffffeffffffffffffffffffffffff60601b1980878609602085015109916ffffffffeffffffffffffffffffffffff60601b19808681868103818d8189890990090896510991818381039189090890811585151694855f14615d4f575050505050600114615cbd5750505050565b6ffffffffeffffffffffffffffffffffff60601b198080809a508699508097985080969381808087819998099d838f94097fffffffff00000001000000000000000000000000fffffffffffffffffffffffc09818088800960030908940960040991818080808087600209810381868009089c80096008098103938b820390089009089409600209905f808080612e7b565b929b50935096506ffffffffeffffffffffffffffffffffff60601b1980808080809c9d50809a995080985080969f508b8009809709958a098180876002098103818381038188800908089d098103938c8203900890090895099009905f808080612e7b565b92918015615e29576ffffffffeffffffffffffffffffffffff60601b197fffffffff00000001000000000000000000000000fffffffffffffffffffffffd615dfb92615f67565b919015615b72576ffffffffeffffffffffffffffffffffff60601b1991829081808280098097099509900990565b505090505f905f90565b9392908015615ec4576ffffffffeffffffffffffffffffffffff60601b19806001969481808080809a9881809981039d8e920908938160018b820392090881818009998a9182099809918180898180877fffffffff00000001000000000000000000000000fffffffffffffffffffffffd09818381038188800908089c09938b820390080908946001099260010990565b5092509190600190600190565b9092919260405192602084526020808501526020604085015260608401527fffffffff00000001000000000000000000000000fffffffffffffffffffffffd60808401526ffffffffeffffffffffffffffffffffff60601b1960a084015260208360c08160055f19fa1561026a576ffffffffeffffffffffffffffffffffff60601b198093918180935180920995098009900991565b91908115615fa2576020925f9260c0926040519286845286808501528660408501526060840152608083015260a082015260055afa905f5190565b5050505f905f9056fea164736f6c634300081d000a

Deployed Bytecode

0x60806040526004361015610015575b3661288157005b5f3560e01c80630f3ebf6e1461024457806312aaac701461023f5780631626ba7e1461023a57806319822f7c146102355780631b71bb6e14610230578063219a260d1461022b57806323d578861461022657806325e5c2431461022157806327258b221461021c57806328495877146102175780632abbf4691461021257806330b1fa3b1461020d5780634223b5c2146102085780636575f6aa146102035780636750aa5f146101fe5780636a1ea88d146101f95780637613e7ba146101f4578063786902f2146101ef578063789ff701146101ea57806384b0196e146101e55780638dd7712f146101e057806394430fa5146101db57806399e1d016146101d6578063a58bb84a146101d1578063ac9650d8146101cc578063b70e36f0146101c7578063b75c7dc6146101c2578063b923614f146101bd578063bf7c5be9146101b8578063c3c16ee4146101b3578063d03c7914146101ae578063e41dae2f146101a9578063e9ae5c53146101a4578063f698da251461019f5763fac750e00361000e5761196a565b611950565b6118a5565b61183d565b61181f565b611678565b611635565b6115f9565b6113fd565b611278565b611174565b61101c565b610fe8565b610e46565b610d9e565b610cc8565b610caf565b610c96565b610c30565b610bcd565b610b9e565b610b34565b610a8e565b610a0e565b610817565b6107b8565b610790565b61070e565b61066a565b610621565b610554565b6103e5565b610393565b610302565b3461026a57602060031936011261026a576020610262600435611984565b604051908152f35b5f80fd5b6003111561027857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9060038210156102785752565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b606060206102ff938184526102ef82850182516102a5565b01519160408082015201906102b2565b90565b3461026a57602060031936011261026a5761032d610321600435611b23565b604051918291826102d7565b0390f35b9181601f8401121561026a5782359167ffffffffffffffff831161026a576020838186019501011161026a57565b90604060031983011261026a57600435916024359067ffffffffffffffff821161026a5761038f91600401610331565b9091565b3461026a5760206103ac6103a63661035f565b91611c5f565b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b908161012091031261026a5790565b3461026a57606060031936011261026a5760043567ffffffffffffffff811161026a576104169036906004016103d6565b60443560243573ffffffffffffffffffffffffffffffffffffffff61043961253c565b1633036105015761032d926104836104d792846104d0956104f1575b5061046d610467610100850185611df0565b90612b26565b9693928561047e8598949398611b23565b6129e9565b9461048d82611984565b95156104e75778ffffffffff000000000000000000000000000000000000000086169788955b73ffffffffffffffffffffffffffffffffffffffff9236916109bd565b951661316d565b6040519081529081906020820190565b60019788956104b3565b5f9081803892335af1505f610455565b7fd663742a000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff81160361026a57565b359061055282610529565b565b3461026a57602060031936011261026a5760043561057181610529565b3033036105f95773ffffffffffffffffffffffffffffffffffffffff167f800000000000000000000000000000000000000000000000000000000000000081177f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600557fea942933e7fb7cb728727281a81e352a20dda96dbc4ee97633a3fa25da48e4ab5f80a2005b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576004355f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368604602052602060405f2054604051908152f35b3461026a57604060031936011261026a5760043561068781610529565b602435903033036105f95773ffffffffffffffffffffffffffffffffffffffff1690815f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686056020528060405f20556040519081527f30346eac03b1c5913bb026e6d8d0f42783a0c706bb2a86916410dc385cc2723660203092a360405160018152602090f35b3461026a57604060031936011261026a5760043561072b81610529565b602435903033036105f957806107568373ffffffffffffffffffffffffffffffffffffffff9361325c565b60405192835216907ff8c1385bb618a432aebbaae5bfab911559154982a64e1750b17b50f5782dc98860203092a360405160018152602090f35b3461026a57602060031936011261026a5760206107ae60043561327b565b6040519015158152f35b3461026a575f60031936011261026a5761032d6040516107d9604082610956565b601581527f556e69737761702e43616c696275722e312e302e30000000000000000000000060208201526040519182916020835260208301906102b2565b3461026a57602060031936011261026a576004356bffffffffffffffffffffffff811680910361026a573033036105f9577f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606546bffffffffffffffffffffffff8116820361088157005b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016177f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606557f0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d315f80a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761093557604052565b6108ec565b6060810190811067ffffffffffffffff82111761093557604052565b90601f601f19910116810190811067ffffffffffffffff82111761093557604052565b6040519061055260c083610956565b60405190610552606083610956565b6003111561026a57565b67ffffffffffffffff811161093557601f01601f191660200190565b9291926109c9826109a1565b916109d76040519384610956565b82948184528183011161026a578281602093845f960137010152565b9080601f8301121561026a578160206102ff933591016109bd565b3461026a57602060031936011261026a5760043567ffffffffffffffff811161026a576040600319823603011261026a57604051610a4b81610919565b8160040135610a5981610997565b8152602482013567ffffffffffffffff811161026a57610a8c926004610a8292369201016109f3565b6020820152611e55565b005b3461026a57602060031936011261026a57600435610aaa611a0c565b5080610ae16318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090565b015490610aec61375e565b1115610b0c576103218168fbb67fda52d4bfb8bf61032d93141502611b23565b7f4e23d035000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576020610262600435610b55612765565b604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b9060206102ff9281815201906102b2565b3461026a575f60031936011261026a5761032d610bb96120b1565b6040519182916020835260208301906102b2565b3461026a57602060031936011261026a5777ffffffffffffffffffffffffffffffffffffffffffffffff600435165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368604602052602060405f2054604051908152f35b3461026a575f60031936011261026a5760206040517f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686008152f35b600319606091011261026a57600435610c8281610529565b90602435610c8f81610529565b9060443590565b3461026a5760206107ae610ca936610c6a565b91612145565b3461026a5760206107ae610cc236610c6a565b91612277565b3461026a575f60031936011261026a577fff00000000000000000000000000000000000000000000000000000000000000610d4f73ffffffffffffffffffffffffffffffffffffffff610d41610d1c612408565b97946040999397919699949294519a8b9a168a5260e060208b015260e08a01906102b2565b9088820360408a01526102b2565b93606087015216608085015260a084015282810360c0840152602080835192838152019201905f5b818110610d85575050500390f35b8251845285945060209384019390920191600101610d77565b3461026a57604060031936011261026a5760043567ffffffffffffffff811161026a57610dcf9036906004016103d6565b73ffffffffffffffffffffffffffffffffffffffff610dec61253c565b16330361050157610e16610e07610467610100840184611df0565b50505050916060810190611df0565b60048193929310610e3957826004610e3492610a8c95019101610fc2565b613489565b633b99b53d5f526004601cfd5b3461026a575f60031936011261026a576020610e6061253c565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b67ffffffffffffffff81116109355760051b60200190565b9080601f8301121561026a57813591610eae83610e7e565b92610ebc6040519485610956565b80845260208085019160051b8301019183831161026a5760208101915b838310610ee857505050505090565b823567ffffffffffffffff811161026a578201906060601f19838803011261026a5760405190610f178261093a565b6020830135610f2581610529565b82526040830135602083015260608301359167ffffffffffffffff831161026a57610f58886020809695819601016109f3565b6040820152815201920191610ed9565b8015150361026a57565b91909160408184031261026a5760405190610f8c82610919565b819381359167ffffffffffffffff831161026a57610fb06020939284938301610e96565b8452013591610fbe83610f68565b0152565b9060208282031261026a57813567ffffffffffffffff811161026a576102ff9201610f72565b602060031936011261026a5760043567ffffffffffffffff811161026a57611017610a8c913690600401610f72565b6125b8565b3461026a57604060031936011261026a576004356024353033036105f95781156110cf576110498261327b565b156110a75760207f55194732cd17a56216773dcef66731844f1900f9b878633e3be2b6cce1e542c991835f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860382528060405f2055604051908152a2005b7fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fb37b2fa0000000000000000000000000000000000000000000000000000000005f5260045ffd5b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061112957505050505090565b9091929394602080611165837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0866001960301875289516102b2565b9701930193019193929061111a565b602060031936011261026a5760043567ffffffffffffffff811161026a573660238201121561026a5780600401359067ffffffffffffffff821161026a576024810190602436918460051b01011161026a576111cf82610e7e565b916111dd6040519384610956565b808352601f196111ec82610e7e565b015f5b8181106112675750505f5b81811061120f576040518061032d86826110f7565b5f8061121c838587612605565b9061122c60405180938193612621565b0390305af461123961262e565b901561125f579060019161124d828761265d565b52611258818661265d565b50016111fa565b602081519101fd5b8060606020809388010152016111ef565b3461026a57602060031936011261026a576004353033036105f9578060401c6112f36112e58277ffffffffffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f2090565b5467ffffffffffffffff1690565b9167ffffffffffffffff81169267ffffffffffffffff81168411156113d55767ffffffffffffffff61ffff91850316116113ad577f4d9dbebf1d909894d9c26fe228c27cec643b2cb490124e5b658f4edd203c20c1926113976113a89377ffffffffffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f2090565b556040519081529081906020820190565b0390a1005b7f24d35a26000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f756688fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a57602060031936011261026a576004353033036105f957805f906114506318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090565b9068fbb67fda52d4bfb8bf84146115ec5783156115dc575b811980549182159260011c5f19810191600183811b179461157057856020525f5260405f20948554928315611561575f97505f19840103611543575b50505055556114b360015b1590565b6110a7576114f06114eb825f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f2090565b6126d3565b5f8181527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205260408120557fe5af7daed5ab2a2dc5f98d53619f05089c0c14d11a6621f6b906a2366c9a7ab35f80a2005b5f1980849383010154928392010155855260408520555f80806114a4565b505050505050506114b3901590565b955050505050600190828154146115c057818101838154146115ac5750600201918254146115a25750600190506114b3565b5f6114b392551590565b6114b3935060025f92019081549055551590565b6114b39250806002835f93019182548155019081549055551590565b5068fbb67fda52d4bfb8bf611468565b63f5a267f15f526004601cfd5b3461026a575f60031936011261026a5760207f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860154604051908152f35b3461026a57602060031936011261026a5773ffffffffffffffffffffffffffffffffffffffff60043561166781610529565b165f526020805f205c604051908152f35b604060031936011261026a5760043567ffffffffffffffff811161026a57806004019060a0600319823603011261026a5760243567ffffffffffffffff811161026a576116c9903690600401610331565b91909273ffffffffffffffffffffffffffffffffffffffff60648301356116ef81610529565b168015908115611815575b50156105f9576084820135801515908161180b575b506117e3576117316114af936117619561172c6024860135613e8f565b613ee0565b9691604461175361174e61174999949699368961368a565b613f20565b6120a5565b960135968661047e89611b23565b6117bb57610a8c94610e34938573ffffffffffffffffffffffffffffffffffffffff6117a46117ab9561179384611984565b9561179d87612dc2565b36916109bd565b93166140d1565b6117b6369180612732565b610f72565b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f0819bdcd000000000000000000000000000000000000000000000000000000005f5260045ffd5b905042115f61170f565b905033145f6116fa565b3461026a57602060031936011261026a5760206107ae600435613709565b3461026a57602060031936011261026a5773ffffffffffffffffffffffffffffffffffffffff60043561186f81610529565b165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368605602052602060405f2054604051908152f35b6118ae3661035f565b6118b9839293613709565b156119285782019160208184031261026a5780359067ffffffffffffffff821161026a57610a8c937eff0000000000000000000000000000000000000000000000000000000000009261190c9201610e96565b916040519261191a84610919565b8352161560208201526125b8565b7f7f181275000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461026a575f60031936011261026a576020610262612765565b3461026a575f60031936011261026a57602061026261375e565b80156119ed576119938161327b565b6119bf577fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205260405f205490565b5079010000000000000000000000000000000000000000000000000090565b60405190611a1982610919565b60606020835f81520152565b90600182811c92168015611a6c575b6020831014611a3f57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611a34565b81601f8201121561026a57805190611a8d826109a1565b92611a9b6040519485610956565b8284526020838301011161026a57815f9260208093018386015e8301015290565b60208183031261026a5780519067ffffffffffffffff821161026a570160408183031261026a5760405191611af083610919565b8151611afb81610997565b8352602082015167ffffffffffffffff811161026a57611b1b9201611a76565b602082015290565b611b2b611a0c565b508015611c5657611b3b8161327b565b611b67577fe57b6304000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f206040515f825492611ba184611a25565b9081845260208401946001811690815f14611c1b5750600114611bde575b505081611bd46102ff94936020930382610956565b8051010190611abc565b5f908152602081209092505b818310611c01575050810160200181611bd4611bbf565b600181602092949394548385880101520191019190611bea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686525050151560051b8201602001905081611bd4611bbf565b506102ff6128b7565b9180611d7e5761773961ffff821904028314611d5757611c7e91612b26565b9391611c8d8396949296611b23565b91611ca28282611c9b6120b1565b8887612b79565b928315611d3b575b50505015611d1357611ce9611cef94611cc283611984565b611ccb81612dc2565b73ffffffffffffffffffffffffffffffffffffffff169436916109bd565b92612e6e565b7f1626ba7e0000000000000000000000000000000000000000000000000000000090565b505050507fffffffff0000000000000000000000000000000000000000000000000000000090565b611d4f935085611d49612765565b91612d60565b5f8080611caa565b5050507f773900010000000000000000000000000000000000000000000000000000000090565b90611d8982826128f1565b611d975790611c7e91612b26565b611da39261047e6128b7565b15611dcc577f1626ba7e0000000000000000000000000000000000000000000000000000000090565b7fffffffff0000000000000000000000000000000000000000000000000000000090565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026a570180359067ffffffffffffffff821161026a5760200191813603831361026a57565b60405190611e50602083610956565b5f8252565b3033036105f957805160038110156102785780611e7360029261026e565b1480611f4a575b611f22577f8df00f8e3bbfb2c3024a60b74e1d4e520f7cbe1da3476726241146ecf6328832611f1d611eab83613318565b92611f07604051611ed181611ec385602083016102d7565b03601f198101835282610956565b611f02865f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860260205260405f2090565b611fda565b611f1084613355565b50604051918291826102d7565b0390a2565b7f41e2e8f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b50602081015173ffffffffffffffffffffffffffffffffffffffff611f7a825192602080309583010191016129d4565b1614611e7a565b818110611f8c575050565b5f8155600101611f81565b9190601f8111611fa657505050565b610552925f5260205f20906020601f840160051c83019310611fd0575b601f0160051c0190611f81565b9091508190611fc3565b919091825167ffffffffffffffff81116109355761200281611ffc8454611a25565b84611f97565b6020601f82116001146120405781906120319394955f92612035575b50505f198260011b9260031b1c19161790565b9055565b015190505f8061201e565b601f19821690612053845f5260205f2090565b915f5b81811061208d57509583600195969710612075575b505050811b019055565b01515f1960f88460031b161c191690555f808061206b565b9192602060018192868b015181550194019201612056565b6102ff90610b55612765565b73ffffffffffffffffffffffffffffffffffffffff6120ce612408565b5094509150939150604051937fc7e4f5b2d381bdfacf8506a24542052ab4e951573cab4ce34bb1c9509c84cbbf60208601527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c6040860152606085015216608083015260a082015260a081526102ff60c082610956565b821561226f5773ffffffffffffffffffffffffffffffffffffffff3091160361224757335f908152602090205c9082821061221f5781835f1973ffffffffffffffffffffffffffffffffffffffff941061220d575b505016905f80808084865af16121ae61262e565b50156121e5576040519081527f3f1beca043a9fe9118bbaeca0035e81e02d6d7cf184bf32fa9dfbd73fdd027c060203092a3600190565b7fb06a467a000000000000000000000000000000000000000000000000000000005f5260045ffd5b61221891033361325c565b5f8361219a565b7fc45cb513000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7d1c29f3000000000000000000000000000000000000000000000000000000005f5260045ffd5b505050600190565b91905f9282156123ff5773ffffffffffffffffffffffffffffffffffffffff3091160361224757335f9081527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368605602052604090205482811061221f575f198110612364575b5073ffffffffffffffffffffffffffffffffffffffff16918080808085875af161230461262e565b501561233c57506040519081527fed1cf8378e55f85e35be72eebdbef1b7347825916e51aa538d1855113f8c259d60203092a3600190565b807fb06a467a0000000000000000000000000000000000000000000000000000000060049252fd5b73ffffffffffffffffffffffffffffffffffffffff919350829003925f93806123ca3373ffffffffffffffffffffffffffffffffffffffff165f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860560205260405f2090565b5560405190815233907f85b16643b7d42712d1470a1ed9822d6e8cadad23eb1141cabefa28da0944c5b790602090a2906122dc565b50505050600190565b7f1f000000000000000000000000000000000000000000000000000000000000009060408051906124398183610956565b600782527f43616c69627572000000000000000000000000000000000000000000000000006020830152805161246f8282610956565b600581527f312e302e3000000000000000000000000000000000000000000000000000000060208201527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368606549293909246923092909160a01b7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000009b1d0af20d8c6d0a44e162d11f9b8f001617915161252f602082610956565b5f80825236602083013790565b7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb71368600547f800000000000000000000000000000000000000000000000000000000000000081161561259f5773ffffffffffffffffffffffffffffffffffffffff1690565b50734337084d9e255ff0702461cf8895ce9e3b5ff10890565b6125c1336135df565b6125ca81613638565b156105f95761055291613489565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9082101561261c5761038f9160051b810190611df0565b6125d8565b908092918237015f815290565b3d15612658573d9061263f826109a1565b9161264d6040519384610956565b82523d5f602084013e565b606090565b805182101561261c5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908160021b917f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116036126ce57565b612671565b6126dd8154611a25565b90816126e7575050565b81601f5f93116001146126f8575055565b8183526020832061271491601f0160051c810190600101611f81565b808252602082209081548360011b905f198560031b1c191617905555565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561026a570190565b7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686065460a01b7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000009b1d0af20d8c6d0a44e162d11f9b8f00161760405160208101917fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647283527fc7e4f5b2d381bdfacf8506a24542052ab4e951573cab4ce34bb1c9509c84cbbf60408301527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608301524660808301523060a083015260c082015260c0815261287b60e082610956565b51902090565b5f3560e01c63bc197c81811463f23a6e6182141763150b7a028214176128ae57633c10b94e5f526004601cfd5b6020526020603cf35b6128bf611a0c565b50604051306020820152602081526128d8604082610956565b604051906128e582610919565b60028252602082015290565b5060418114908115612901575090565b604091501490565b919082604091031261026a576020825192015190565b60208183031261026a5780359067ffffffffffffffff821161026a57019060c08282031261026a5761294f610979565b91803567ffffffffffffffff811161026a578261296d9183016109f3565b8352602081013567ffffffffffffffff811161026a5760a0926129919183016109f3565b6020840152604081013560408401526060810135606084015260808101356080840152013560a082015290565b919082604091031261026a576020823592013590565b9081602091031261026a57516102ff81610529565b9290600284516129f88161026e565b612a018161026e565b03612a6a579073ffffffffffffffffffffffffffffffffffffffff92612a2692613b2f565b169081612a335750505f90565b612a4d6020612a66920151602080825183010191016129d4565b73ffffffffffffffffffffffffffffffffffffffff1690565b1490565b8351612a758161026e565b612a7e8161026e565b612abb57612ab690612aae612aa360206102ff97015160208082518301019101612909565b9590948101906129be565b929091613aec565b613b04565b60018451612ac88161026e565b612ad18161026e565b03612b1e57611ec3612b19612b04612af960206102ff98015160208082518301019101612909565b96909581019061291f565b92604051928391602083019190602083019252565b6138de565b505050505f90565b9190823592612b358282613bbd565b9093819363ffffffff60408501351684019063ffffffff82351694602080840193870101910110610e3957604090939210612b6c57565b634be6321b5f526004601cfd5b9091939293612b888486614660565b949093612b9f602088013592604089013598614690565b9091612bde8985604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b03612d5457612bec91613c80565b82959299939199158015612d4c575b612d3e57611ec3612cd9612c266102ff9c612c1e612cfc96612d389b36916109bd565b9436916109bd565b604051928391605c612c6360208501977f5479706564446174615369676e280000000000000000000000000000000000008952602e860190613809565b7f20636f6e74656e74732c737472696e67206e616d652c737472696e672076657281527f73696f6e2c75696e7432353620636861696e49642c616464726573732076657260208201527f696679696e67436f6e74726163742c627974657333322073616c74290000000060408201520190613809565b51902092611ec36040519384926020840196875260408401526060830190613809565b51902090604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b906129e9565b505050505050505050505f90565b508015612bfb565b50505050505050505f90565b906102ff949392612d3891604090601c60208351612d7e8582610956565b828152017f506572736f6e616c5369676e28627974657320707265666978656429000000008152209180519160208301938452818301528152612cfc606082610956565b612dcb90613e70565b90612dd35750565b64ffffffffff907f48c76fe1000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b51907fffffffff000000000000000000000000000000000000000000000000000000008216820361026a57565b9081602091031261026a576102ff90612e06565b6102ff93926060928252602082015281604082015201906102b2565b6040513d5f823e3d90fd5b9290919260048116612e81575b50505050565b612ed39373ffffffffffffffffffffffffffffffffffffffff602094604051968795869485937f9ac4eafd00000000000000000000000000000000000000000000000000000000855260048501612e47565b0392165afa908115612f91577f9ac4eafd00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91612f62575b501603612f3a575f808080612e7b565b7f1e048e1d000000000000000000000000000000000000000000000000000000005f5260045ffd5b612f84915060203d602011612f8a575b612f7c8183610956565b810190612e33565b5f612f2a565b503d612f72565b612e63565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026a57016020813591019167ffffffffffffffff821161026a57813603831361026a57565b601f8260209493601f1993818652868601375f8582860101520116010190565b91613155906102ff96949592845260a0602085015261304560a0850161302b83610547565b73ffffffffffffffffffffffffffffffffffffffff169052565b602081013560c08501526131246131186130b961307b6130686040860186612f96565b61012060e08b01526101c08a0191612fe6565b6130886060860186612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608a8403016101008b0152612fe6565b608084013561012088015260a084013561014088015260c08401356101608801526130e760e0850185612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60898403016101808a0152612fe6565b91610100810190612f96565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60868403016101a0870152612fe6565b936040830152606082015260808184039101526102b2565b9190939460028316613182575b505050505050565b6020946131d473ffffffffffffffffffffffffffffffffffffffff92604051988997889687957f9e364dba00000000000000000000000000000000000000000000000000000000875260048701613006565b0392165afa908115612f91577f9e364dba00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f9161323d575b501603612f3a575f808080808061317a565b613256915060203d602011612f8a57612f7c8183610956565b5f61322b565b73ffffffffffffffffffffffffffffffffffffffff165f5260205f205d565b6132b07f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686016318fb58646004525f5260245f2090565b68fbb67fda52d4bfb8bf82146115ec578115613307575b801954156132de576020525f5260405f2054151590565b9060019181815414613302578183820154146133025760020154146102ff57505f90565b505090565b68fbb67fda52d4bfb8bf91506132c7565b8051906003821015610278576020015160208151910120604051906133416020830180946102a5565b60408201526040815261287b606082610956565b905f9161338d7f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686016318fb58646004525f5260245f2090565b9068fbb67fda52d4bfb8bf81146115ec578015613479575b8119918254918160205282156133ed575b805f5260405f20928354156133cc575050505050565b9091929394955060011c8092015560010180915560011b6001179055600190565b91508054801561347057828114612e7b57600182018054908115613462575083811461345b576002830191825492831561344c575084831461317a575f52600160405f20555f52600260405f20555f52600360405f20556007916133b6565b95505050505091925055600190565b5050505050565b945050505091925055600190565b50555060019150565b5068fbb67fda52d4bfb8bf6133a5565b5f5b81518051821015612e7b57816134a09161265d565b51805173ffffffffffffffffffffffffffffffffffffffff16806135d9575030905b6134cb85611984565b60ff60c882901c1615806135ba575b6135925785925f8073ffffffffffffffffffffffffffffffffffffffff613537941694602081019361351760408651930192835190838b8b6147d9565b9451915191602083519301915af1928361352f61262e565b958692614966565b1580613585575b61354b575060010161348b565b613581906040519182917fa5fa8d2b00000000000000000000000000000000000000000000000000000000835260048301610b8d565b0390fd5b506020830151151561353e565b7f3ceb88d9000000000000000000000000000000000000000000000000000000005f5260045ffd5b503073ffffffffffffffffffffffffffffffffffffffff8416146134da565b906134c2565b73ffffffffffffffffffffffffffffffffffffffff16308114613633576102ff9060405190602082015260208152613618604082610956565b6040519061362582610919565b600282526020820152613318565b505f90565b8015613684576136478161327b565b15613633575f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860360205261367f60405f2054613e70565b501590565b50600190565b91909160a08184031261026a576040519060a0820182811067ffffffffffffffff82111761093557604052819381359167ffffffffffffffff831161026a576136d96080939284938301610f72565b8452602081013560208501526040810135604085015260608101356136fd81610529565b60608501520135910152565b7f01000000000000000000000000000000000000000000000000000000000000008114908115613737575090565b7f010100000000000000000000000000000000000000000000000000000000000091501490565b6318fb58646004527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb713686015f5260245f2090811954918260011c9215159080541560026001830154159201541592156137b457505050565b90919293505f906137da57506001906137d557506002906102ff5750600390565b919050565b92915050565b90601582018092116126ce57565b90600282018092116126ce57565b919082018092116126ce57565b805191908290602001825e015f815290565b90610552600161385b936040519485917f226368616c6c656e6765223a22000000000000000000000000000000000000006020840152602d830190613809565b7f22000000000000000000000000000000000000000000000000000000000000008152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1810185520183610956565b80516020101561261c5760400190565b6138c89060209392613809565b9081520190565b9081602091031261026a575190565b92919060a081019384517f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a810613ad95760208201907fff1a2a9176d650e4a99dedb58f1793003935130579fe17b5a3f698ac5b00e63461394d83516060860151613947816137e0565b91614c42565b6020815191012003613ae25761396561396a9161419b565b61381b565b61397f825160408501516139478451826137fc565b60208151910120906020815191012003613ad9577f0100000000000000000000000000000000000000000000000000000000000000806139e86139c285516138ab565b517fff000000000000000000000000000000000000000000000000000000000000001690565b1603613ad9575f613a026020925160405191828092613809565b039060025afa15612f915760205f613a378151613a2b8551611ec36040519384928884016138bb565b60405191828092613809565b039060025afa15612f915760805f519101935f80865185613a888551611ec38a60405194859360208501978c899192608093969594919660a084019784526020840152604083015260608201520152565b51906101005afa94613a9861262e565b80519680613ad0575b613ab457506102ff955051905191614202565b600196612a6696508101602090810195500192506138cf915050565b50861515613aa1565b50505050505f90565b5050505050505f90565b5f5260206001815f60025afa51903d15613b0257565bfe5b93929190613b15848484848961435c565b90959015613b2557505050505090565b6102ff9550614417565b604080515f95949093918114613b7a57604114613b4b57505050565b604080929395508101355f1a60205281375b5f526020604060805f60015afa505f6060523d6060185191604052565b507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91929450602081013590601b8260ff1c016020523560405216606052613b5d565b909163ffffffff60208301351682019263ffffffff84351692602080860195850101910110610e3957565b905f1982019182116126ce57565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255103907fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255182116126ce57565b9082101561261c570190565b80156126ce575f190190565b90929192831161026a579190565b9093929384831161026a57841161026a578101920390565b9080613c93575b50505f905f905f905f90565b7f29000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000613d11613ceb613ce485613be8565b8587613c42565b357fff000000000000000000000000000000000000000000000000000000000000001690565b1603613db7575f5b818110613d2c575b5050505b5f80613c87565b613d3a613ceb828486613c42565b7fff0000000000000000000000000000000000000000000000000000000000000081167f280000000000000000000000000000000000000000000000000000000000000003613da257508015613d9d57613d95908284613c5a565b939093929190565b613d21565b613dab906146bb565b613d9d57600101613d19565b9081805b613dc8575b505050613d25565b613de2613ceb613ddb8396949596613be8565b8686613c42565b7fff0000000000000000000000000000000000000000000000000000000000000081167f290000000000000000000000000000000000000000000000000000000000000003613e4b575080613e3c85613e44938187613c68565b959094613c5a565b9293929091565b613e5890949392946146bb565b613e6b57613e6590613c4e565b80613dbb565b613dc0565b60a01c64ffffffffff16908115613e88574282109190565b5f91508190565b8060401c5f527f3b86514c5c56b21f08d8e56ab090292e07c2483b3e667a2a45849dcb7136860460205260405f208054915f1983146126ce5767ffffffffffffffff9160018401905516036113d557565b909163ffffffff82351682019063ffffffff8235169060208084019383010184860110610e3957613f15604093958395613bbd565b9390939210612b6c57565b60c1610100613f326040519182610956565b8181527f290000000000000000000000000000000000000000000000000000000000000060e060208301927f5369676e65644261746368656443616c6c284261746368656443616c6c20626184527f746368656443616c6c2c75696e74323536206e6f6e63652c627974657333322060408201527f6b6579486173682c61646472657373206578656375746f722c75696e7432353660608201527f20646561646c696e65294261746368656443616c6c2843616c6c5b5d2063616c60808201527f6c732c626f6f6c207265766572744f6e4661696c7572652943616c6c2861646460a08201527f7265737320746f2c75696e743235362076616c75652c6279746573206461746160c08201520152209061287b61404f8251614a51565b611ec36020840151936040810151906080614081606083015173ffffffffffffffffffffffffffffffffffffffff1690565b9101519160405196879560208701998a929360a09473ffffffffffffffffffffffffffffffffffffffff93989796929860c086019986526020860152604085015260608401521660808201520152565b92909192600181166140e35750505050565b6141359373ffffffffffffffffffffffffffffffffffffffff602094604051968795869485937f33dd593c00000000000000000000000000000000000000000000000000000000855260048501612e47565b0392165afa908115612f91577f33dd593c00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91612f6257501603612f3a575f808080612e7b565b6040516102ff916141ad606083610956565b604082527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208301527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f6040830152614cec565b93919092938315801561431d575b8015614315575b80156142eb575b613ad95761422c8386614d93565b15613ad95760405191602083526020808401526020604084015260608301527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f60808301527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255160a083015260208260c08160055f19fa1561026a577fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551946142e593866142df945181818909940991614e5f565b91613bf6565b90081590565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255182101561421e565b508115614217565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551841015614210565b9081602091031261026a57516102ff81610f68565b91909361436c6114af83876156fe565b8015614404575b6143f8575f94611ec36143b29287966040519586946020860198899192608093969594919660a084019784526020840152604083015260608201520152565b51906101005afa6143c161262e565b90806143ed575b156143e657806020806143e093518301019101614347565b90600190565b505f905f90565b5060208151146143c8565b50505050505f90600190565b506144126114af8286615775565b614373565b909392919261442684866156fe565b15801561464f575b613ad9577fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255161461c612a669561461161462896614469615804565b95614472610988565b5f81525f60208201525f6040820152875261448b610988565b9182526020820152600160408201526144a48660200190565b9081526144af610988565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29681527f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5602082015260016040820152608087019081526146076145138351615ac2565b604089019081526145f86145e961452a8551615ac2565b6101008c0190815261453f8751855190615aff565b9560608d019687528c61455f6145588a51845190615aff565b9160a00190565b528c6145786145718751845190615aff565b9160c00190565b528c61459161458a8951845190615aff565b9160e00190565b528c6145ab6145a38a51855190615aff565b916101200190565b528c6145c56145bd8751855190615aff565b916101400190565b528c6145df6145d78951855190615aff565b916101600190565b5251905190615aff565b6101808b018181529551615aff565b6101a08a015251835190615aff565b6101c088016145df565b6101e0850152615b1e565b8181880993099061584a565b507fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551900690565b5061465a8184615775565b1561442e565b909163ffffffff82351682019263ffffffff8435169260208086019585010191011061468857565b9150505f5f91565b909163ffffffff60608301351682019263ffffffff8435169260208086019585010191011061468857565b7fff0000000000000000000000000000000000000000000000000000000000000016801590811561477a575b8115614750575b8115614726575b81156146ff575090565b7f290000000000000000000000000000000000000000000000000000000000000091501490565b7f2800000000000000000000000000000000000000000000000000000000000000811491506146f5565b7f2c00000000000000000000000000000000000000000000000000000000000000811491506146ee565b7f2000000000000000000000000000000000000000000000000000000000000000811491506146e7565b91909160408184031261026a576147ba81612e06565b92602082015167ffffffffffffffff811161026a576102ff9201611a76565b6060959490929190600884166147f0575050505050565b5f94965073ffffffffffffffffffffffffffffffffffffffff8094939261486087936040519a8b98899788957fec9b4ee4000000000000000000000000000000000000000000000000000000008752600487015216602485015260448401526080606484015260848301906102b2565b0393165af18015612f91575f925f916148c9575b507fffffffff000000000000000000000000000000000000000000000000000000007fec9b4ee40000000000000000000000000000000000000000000000000000000091931603612f3a575f8080808061345b565b7fffffffff0000000000000000000000000000000000000000000000000000000093507fec9b4ee400000000000000000000000000000000000000000000000000000000915061492a903d805f833e6149228183610956565b8101906147a4565b9390939150614874565b926102ff9492614958928552151560208501526080604085015260808401906102b2565b9160608184039101526102b2565b90929160108216614978575050505050565b5f73ffffffffffffffffffffffffffffffffffffffff6020956149ca604051988997889687947fc82b175900000000000000000000000000000000000000000000000000000000865260048601614934565b0393165af1908115612f91577fc82b175900000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91614a32575b501603612f3a575f8080808061345b565b614a4b915060203d602011612f8a57612f7c8183610956565b5f614a21565b60806057604051614a63608082610956565b8181527f6e743235362076616c75652c6279746573206461746129000000000000000000606060208301927f4261746368656443616c6c2843616c6c5b5d2063616c6c732c626f6f6c20726584527f766572744f6e4661696c7572652943616c6c286164647265737320746f2c75696040820152015220908251805194601f19614b05614aef88610e7e565b97614afd604051998a610956565b808952610e7e565b013660208801376060935f5b8351811015614bee5780614b276001928661265d565b516029604051614b378a82610956565b8181527f7465732064617461290000000000000000000000000000000000000000000000604060208301927f43616c6c286164647265737320746f2c75696e743235362076616c75652c627984520152209073ffffffffffffffffffffffffffffffffffffffff81511690604060208201519101516020815191012090604051926020840194855260408401528a83015288820152878152614bda60a082610956565b519020614be7828b61265d565b5201614b11565b509493509461287b9250614c1f9150602090604051614c1481611ec3858201809561595b565b519020930151151590565b604080516020810195865290810193909352151560608301528160808101611ec3565b805160609493929083811115614cb3575b81811115614cab575b50828110614c6957505050565b6040519450918290039101601f19601f830181165b8083015181870152018015614c9657601f1990614c7e565b505060408184015f6020820152016040528252565b90505f614c5c565b925082614c53565b90614cc5826109a1565b614cd26040519182610956565b828152601f19614ce282946109a1565b0190602036910137565b90815115614d895790614d19614d14614d0d614d08845161269e565b6137ee565b6003900490565b614cbb565b916020830190828051019060208201928351945f85525b838110614d3f57505050505290565b600360049101916001603f845182828260121c16880101518453828282600c1c16880101518385015382828260061c16880101516002850153168501015160038201530190614d30565b50506102ff611e41565b6ffffffffeffffffffffffffffffffffff60601b198110801590614e41575b8015614e30575b614e2a576ffffffffeffffffffffffffffffffffff60601b197f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b818381807fffffffff00000001000000000000000000000000fffffffffffffffffffffffc81970991818180090908089180091490565b50505f90565b5080158015614db957508115614db9565b506ffffffffeffffffffffffffffffffffff60601b19821015614db2565b90915f925f9160ff958115806156f6575b6156eb57614e7e8386615988565b9490978815806156e3575b615695575b83811c60028460fe1c16015b1561567d57600184821c16600284831c60011b160160018114615632575b60028114615625575b60031461561a575b5f1990969493929196019460019889975b875f1911614f715750505050505050505060405191606083015260208252602080830152602060408301527fffffffff00000001000000000000000000000000fffffffffffffffffffffffd60808301526ffffffffeffffffffffffffffffffffff60601b1960a083015260208260c08160055f19fa1561026a576ffffffffeffffffffffffffffffffffff60601b199151900990565b6ffffffffeffffffffffffffffffffffff60601b198160029c989a9c9b959697999b09936ffffffffeffffffffffffffffffffffff60601b1985800980956ffffffffeffffffffffffffffffffffff60601b19828409966ffffffffeffffffffffffffffffffffff60601b199109916ffffffffeffffffffffffffffffffffff60601b198a8208908a6ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b19906003099c6ffffffffeffffffffffffffffffffffff60601b19908309986ffffffffeffffffffffffffffffffffff60601b1991099b6ffffffffeffffffffffffffffffffffff60601b19867fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b19828009906ffffffffeffffffffffffffffffffffff60601b199108956ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199087086ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b1981938309906ffffffffeffffffffffffffffffffffff60601b19910891878c1c600116878d1c60011b6002160180156155f557600181146155aa575b6002811461559f575b600314615596575b8c15615581578c916ffffffffeffffffffffffffffffffffff60601b198085818d819609089388820392090894811561536c575b6ffffffffeffffffffffffffffffffffff60601b19868009986ffffffffeffffffffffffffffffffffff60601b198a9788099d8e976ffffffffeffffffffffffffffffffffff60601b1991099d6ffffffffeffffffffffffffffffffffff60601b199109986ffffffffeffffffffffffffffffffffff60601b199109916ffffffffeffffffffffffffffffffffff60601b19837fffffffff00000001000000000000000000000000fffffffffffffffffffffffd09866ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b19848009906ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b199108956ffffffffeffffffffffffffffffffffff60601b19910991856ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b199109906ffffffffeffffffffffffffffffffffff60601b19910892985f19905b0196949392979597614eda565b8c861561537957506151ce565b989150919a94506ffffffffeffffffffffffffffffffffff60601b198b7fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b198180099283916ffffffffeffffffffffffffffffffffff60601b19838309946ffffffffeffffffffffffffffffffffff60601b1991099d8e916ffffffffeffffffffffffffffffffffff60601b198281038208916ffffffffeffffffffffffffffffffffff60601b199108906ffffffffeffffffffffffffffffffffff60601b1991096ffffffffeffffffffffffffffffffffff60601b1990600309926ffffffffeffffffffffffffffffffffff60601b199109986ffffffffeffffffffffffffffffffffff60601b1991099b6ffffffffeffffffffffffffffffffffff60601b19837fffffffff00000001000000000000000000000000fffffffffffffffffffffffd096ffffffffeffffffffffffffffffffffff60601b19838009906ffffffffeffffffffffffffffffffffff60601b1991089b6ffffffffeffffffffffffffffffffffff60601b199109918b6ffffffffeffffffffffffffffffffffff60601b19036ffffffffeffffffffffffffffffffffff60601b1991086ffffffffeffffffffffffffffffffffff60601b199109906ffffffffeffffffffffffffffffffffff60601b199108925f199061535f565b60019c50909a8c98509094505f19915061535f565b5050818361519a565b8b92508a9150615192565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29692507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f59150615189565b5050505f19906ffffffffeffffffffffffffffffffffff60601b199a949a039361535f565b889750859150614ec9565b9697508796859250614ec1565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29698507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f59250614eb8565b5f1901600184821c16600284831c60011b1601614e9a565b91927fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551919382039008915f918315806156db575b15614e8e575050505050505050505f90565b5060016156c9565b508515614e89565b505050505050505f90565b508015614e70565b90811515918261574b575b5081615741575b81615719575090565b7f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a89150111590565b8015159150615710565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325511191505f615709565b6ffffffffeffffffffffffffffffffffff60601b1980807f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b8185817fffffffff00000001000000000000000000000000fffffffffffffffffffffffc81838009080908818580091493109110161690565b604051906157f38261093a565b5f6040838281528260208201520152565b604051906102006158158184610956565b825f5b82811061582457505050565b60209061582f6157e6565b8184015201615818565b90601081101561261c5760051b0190565b5f9392849283929183915b6080831061586b575050505061038f9293615db4565b85615939575b600c61587d8260fc1c90565b16600361588a8460fe1c90565b161760406158988287615839565b5101516158c0575b506158b76158b060019260021b90565b9260021b90565b92019190615855565b959194909782155f1461590f575050506158da8483615839565b51519260016158b76158b0604061590060206158f68b8a615839565b5101519988615839565b5101519796995b9250506158a0565b6158b0959260019261592e926159286158b79a89615839565b51615c0b565b979196909699615907565b969461594a91946159509396615b84565b91615b84565b949193909396615871565b80516020909101905f5b8181106159725750505090565b8251845260209384019390920191600101615965565b91907f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2967f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5918015615abc578461038f9495831480615ab3575b15615a9e5750506ffffffffeffffffffffffffffffffffff60601b1982600209916ffffffffeffffffffffffffffffffffff60601b198084800993818080808881818a09950996817fffffffff00000001000000000000000000000000fffffffffffffffffffffffe816001840892080960030981808080867fffffffff00000001000000000000000000000000fffffffffffffffffffffffd0981858009089681600181818c099b099809810393868203900890090890615ed1565b909192615aaa93615e33565b92909190615ed1565b508184146159e1565b50925090565b615ae290615ace6157e6565b508051906040602082015191015191615b84565b9060405192615af08461093a565b83526020830152604082015290565b615ae291615b0b6157e6565b5080516040602083015192015192615c0b565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325517fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f615b6992615f67565b9015615b725790565b634e487b715f5260126020526024601cfd5b9290916ffffffffeffffffffffffffffffffffff60601b1980918180868009968180808a818080808a800980097fffffffff00000001000000000000000000000000fffffffffffffffffffffffc09818088800960030908940960040991818080808087600209810381868009089c80096008098103938b82039008900908940960020990565b91939092935f945f945f946040810151906ffffffffeffffffffffffffffffffffff60601b198280096ffffffffeffffffffffffffffffffffff60601b19858009926ffffffffeffffffffffffffffffffffff60601b1980878609602085015109916ffffffffeffffffffffffffffffffffff60601b19808681868103818d8189890990090896510991818381039189090890811585151694855f14615d4f575050505050600114615cbd5750505050565b6ffffffffeffffffffffffffffffffffff60601b198080809a508699508097985080969381808087819998099d838f94097fffffffff00000001000000000000000000000000fffffffffffffffffffffffc09818088800960030908940960040991818080808087600209810381868009089c80096008098103938b820390089009089409600209905f808080612e7b565b929b50935096506ffffffffeffffffffffffffffffffffff60601b1980808080809c9d50809a995080985080969f508b8009809709958a098180876002098103818381038188800908089d098103938c8203900890090895099009905f808080612e7b565b92918015615e29576ffffffffeffffffffffffffffffffffff60601b197fffffffff00000001000000000000000000000000fffffffffffffffffffffffd615dfb92615f67565b919015615b72576ffffffffeffffffffffffffffffffffff60601b1991829081808280098097099509900990565b505090505f905f90565b9392908015615ec4576ffffffffeffffffffffffffffffffffff60601b19806001969481808080809a9881809981039d8e920908938160018b820392090881818009998a9182099809918180898180877fffffffff00000001000000000000000000000000fffffffffffffffffffffffd09818381038188800908089c09938b820390080908946001099260010990565b5092509190600190600190565b9092919260405192602084526020808501526020604085015260608401527fffffffff00000001000000000000000000000000fffffffffffffffffffffffd60808401526ffffffffeffffffffffffffffffffffff60601b1960a084015260208360c08160055f19fa1561026a576ffffffffeffffffffffffffffffffffff60601b198093918180935180920995098009900991565b91908115615fa2576020925f9260c0926040519286845286808501528660408501526060840152608083015260a082015260055afa905f5190565b5050505f905f9056fea164736f6c634300081d000a

Deployed Bytecode Sourcemap

2410:112:23:-:0;;;;;;;;;-1:-1:-1;2410:112:23;1266:232:12;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;2410:112:23;;;;-1:-1:-1;2410:112:23;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;826:13:26;;:::i;:::-;2410:112:23;812:10:26;:27;808:55;;2410:112:23;1508:275:26;6065:33:22;6456:96;1508:275:26;;416:10:25;1508:275:26;;;2410:112:23;5793:16:22;:47;:16;;;;;;:::i;:::-;:47;;:::i;:::-;6025:15;;;;;;;;;;;:::i;:::-;6065:33;:::i;:::-;6129:23;;;;:::i;:::-;6347:98;;;;2410:112:23;;;6347:98:22;;;;2410:112:23;;;416:10:25;;:::i;:::-;1756:61:57;;6456:96:22;:::i;:::-;2410:112:23;;;;;;;;;;;;;6347:98:22;676:1:26;6347:98:22;;;;;1508:275:26;-1:-1:-1;1508:275:26;;;;812:10;;1508:275;;;;;;808:55;848:15;-1:-1:-1;848:15:26;2410:112:23;-1:-1:-1;848:15:26;2410:112:23;;;;;;;:::o;:::-;;;;;;:::i;:::-;:::o;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::i;:::-;467:4:21;445:10;:27;441:54;;2410:112:23;;321:8:51;473:53;;997:38:26;2410:112:23;1050:29:26;-1:-1:-1;1050:29:26;;2410:112:23;441:54:21;481:14;-1:-1:-1;481:14:21;2410:112:23;-1:-1:-1;481:14:21;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;;-1:-1:-1;2410:112:23;346:62:33;2410:112:23;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::i;:::-;;;467:4:21;;445:10;:27;441:54;;2410:112:23;;;;-1:-1:-1;2410:112:23;796:15:30;2410:112:23;;;;-1:-1:-1;2410:112:23;;;;;;;844:45:30;2410:112:23;467:4:21;844:45:30;;2410:112:23;;906:4:30;2410:112:23;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::i;:::-;;;467:4:21;;445:10;:27;441:54;;1098:6:30;;;2410:112:23;1098:6:30;;:::i;:::-;2410:112:23;;;;;;467:4:21;1120:54:30;2410:112:23;467:4:21;1120:54:30;;2410:112:23;;906:4:30;2410:112:23;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;2720:27:31;2410:112:23;;2720:27:31;:::i;:::-;2410:112:23;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;467:4:21;445:10;:27;441:54;;4088:11:24;2410:112:23;;;;4078:21:24;;4074:203;;2410:112:23;4074:203:24;2410:112:23;;;4088:11:24;2410:112:23;4245:21:24;-1:-1:-1;4245:21:24;;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;-1:-1:-1;2410:112:23;;;:::o;:::-;;;;;;;;-1:-1:-1;;2410:112:23;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2410:112:23;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;834:278:31;2410:112:23;;;;;;;;;:::i;:::-;;;;;834:278:31;:::i;:::-;2410:112:23;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;:::i;:::-;;29029:14:15;;31914:149;;;1994:9:31;31914:149:15;;;;;31787:282;;29029:14;29096:134;;29248:11;;;:::i;:::-;-1:-1:-1;29243:16:15;29239:47;;1987:23:31;29096:134:15;;2410:112:23;29096:134:15;;;;1987:23:31;:::i;29239:47:15:-;29268:18;-1:-1:-1;29268:18:15;2410:112:23;-1:-1:-1;29268:18:15;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;3913:57:24;2410:112:23;;3946:17:24;;:::i;:::-;3445:249:7;3326:374;3445:249;;;;;;;;;;;;;;;3326:374;;2410:112:23;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;-1:-1:-1;2410:112:23;1186:19:33;2410:112:23;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;601:66:27;2410:112:23;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;:::i;:::-;;826:13:26;;:::i;:::-;2410:112:23;812:10:26;:27;808:55;;4813:15:22;4647:47;:16;;;;;;:::i;:47::-;4813:15;;;;;;;;;;:::i;:::-;2410:112:23;820:264:49;;;;;;;4890:40:22;2410:112:23;4890:40:22;;4968:7;4890:40;;820:264:49;;4890:40:22;:::i;:::-;4968:7;:::i;820:264:49:-;;-1:-1:-1;820:264:49;2410:112:23;820:264:49;;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;467:4:21;445:10;:27;441:54;;1084:24:53;;1233:53:31;;2720:27;;;:::i;:::-;1300:22;1296:52;;2410:112:23;1404:37:31;2410:112:23;;-1:-1:-1;2410:112:23;1358:11:31;2410:112:23;;;;-1:-1:-1;2410:112:23;;;;;;;1404:37:31;2410:112:23;1296:52:31;1331:17;-1:-1:-1;1331:17:31;2410:112:23;-1:-1:-1;1331:17:31;1233:53;1265:21;-1:-1:-1;1265:21:31;2410:112:23;-1:-1:-1;1265:21:31;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;;2410:112:23;;;:::i;:::-;;-1:-1:-1;2410:112:23;;;;;;444:13:32;;-1:-1:-1;459:15:32;;;;;;2410:112:23;;;;;;;:::i;476:3:32:-;-1:-1:-1;560:7:32;;;;;;:::i;:::-;2410:112:23;;;;;;;;;:::i;:::-;533:35:32;541:4;;533:35;;;;:::i;:::-;587:8;;583:182;;779:19;2410:112:23;779:19:32;;;;;:::i;:::-;;;;;;:::i;:::-;;2410:112:23;444:13:32;;583:182;2410:112:23;662:89:32;;;;;2410:112:23;;;;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;467:4:21;445:10;:27;441:54;;2410:112:23;554:2:33;2410:112:23;587:32:33;594:24;;2410:112:23;;;;594:19:33;2410:112:23;;;;;;;594:24:33;2410:112:23;;;;;587:32:33;2410:112:23;;;;;;;;678:23:33;;;674:50;;2410:112:23;;;;;;895:24:33;891:60;;1022:26;971:24;;1022:26;971:24;2410:112:23;;;;594:19:33;2410:112:23;;;;;;;971:24:33;2410:112:23;554:2:33;2410:112:23;;;;;;;;;;;;1022:26:33;;;;2410:112:23;891:60:33;928:23;-1:-1:-1;928:23:33;2410:112:23;-1:-1:-1;928:23:33;674:50;710:14;-1:-1:-1;710:14:33;2410:112:23;-1:-1:-1;710:14:33;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;;467:4:21;445:10;:27;441:54;;1555:25:31;-1:-1:-1;19434:14:15;;31914:149;;;1994:9:31;31914:149:15;;;;;31787:282;;19434:14;19501:1836;;;;;;;;;;2410:112:23;19501:1836:15;;;;;;;;;;-1:-1:-1;;19501:1836:15;;;;;;;;;;;;2410:112:23;19501:1836:15;-1:-1:-1;19501:1836:15;;-1:-1:-1;19501:1836:15;;;;;;;;;-1:-1:-1;19501:1836:15;;-1:-1:-1;;19501:1836:15;;;;;;;;;;;1554:26:31;19501:1836:15;;1554:26:31;;2410:112:23;1554:26:31;1550:56;;1616:26;1623:19;;2410:112:23;;1623:10:31;2410:112:23;;;;;;;1623:19:31;1616:26;:::i;:::-;-1:-1:-1;2410:112:23;;;1652:11:31;2410:112:23;;;;;;1710:16:31;-1:-1:-1;1710:16:31;;2410:112:23;19501:1836:15;-1:-1:-1;;19501:1836:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1554:26:31;19501:1836:15;1554:26:31;;2410:112:23;19501:1836:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1554:26:31;;-1:-1:-1;1554:26:31;2410:112:23;19501:1836:15;-1:-1:-1;1554:26:31;19501:1836:15;;1554:26:31;;2410:112:23;19501:1836:15;1554:26:31;19501:1836:15;;;-1:-1:-1;19501:1836:15;;;;;;;;1554:26:31;;2410:112:23;19501:1836:15;1554:26:31;19501:1836:15;;;;;-1:-1:-1;19501:1836:15;;;;;;;;;;;;;;1554:26:31;;2410:112:23;19501:1836:15;;;;;;;-1:-1:-1;19501:1836:15;2410:112:23;19501:1836:15;;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;608:44:31;2410:112:23;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;706:157:60;2410:112:23;;;;;:::i;:::-;706:157:60;-1:-1:-1;706:157:60;2410:112:23;706:157:60;-1:-1:-1;706:157:60;1075:77;2410:112:23;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3073:26:22;;;2410:112:23;3073:26:22;;;2410:112:23;;;;:::i;:::-;;11568:22:22;;:48;;;;;2410:112:23;3054:46:22;;3050:73;;10583:26;;;2410:112:23;10623:13:22;;;:43;;;;2410:112:23;10619:74:22;;;10803:37;10993:29;10714:23;11036:8;10714:23;;2410:112:23;10714:23:22;;2410:112:23;10714:23:22;:::i;:::-;10803:37;:::i;:::-;2410:112:23;;10942:25:22;10868:39;10882:24;2410:112:23;;;;;;;;:::i;:::-;10882:24:22;:::i;:::-;10868:39;:::i;:::-;10942:25;;2410:112:23;10935:33:22;;;;;:::i;11036:8::-;11032:48;;3202:71;11111:41;2410:112:23;11111:41:22;;2410:112:23;416:10:25;11195:87:22;11111:41;;;;:::i;:::-;11175:8;;;;:::i;:::-;2410:112:23;416:10:25;;:::i;:::-;1756:61:57;;11195:87:22;:::i;:::-;3216:29;2410:112:23;3216:29:22;;;:::i;:::-;2410:112:23;:::i;11032:48:22:-;11053:27;-1:-1:-1;11053:27:22;2410:112:23;-1:-1:-1;11053:27:22;10619:74;10675:18;-1:-1:-1;10675:18:22;2410:112:23;-1:-1:-1;10675:18:22;10623:43;10640:15;;;:26;10623:43;;;11568:48;11606:10;;;11594:22;11568:48;;;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;814:20:29;2410:112:23;;814:20:29;:::i;2410:112:23:-;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;:::i;:::-;;-1:-1:-1;2410:112:23;593:68:30;2410:112:23;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;:::i;:::-;3417:20:22;;;;;:::i;:::-;3416:21;3412:69;;3513:35;;2410:112:23;;;;;;;;;;;;;;;;3677:11:22;2410:112:23;779:66:54;2410:112:23;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;1657:24:54;:29;2410:112:23;3591:68:22;;2410:112:23;3677:11:22;:::i;3412:69::-;3446:35;-1:-1:-1;3446:35:22;2410:112:23;-1:-1:-1;3446:35:22;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;2410:112:23;;;;;;1843:18:31;;:::i;2348:248::-;1084:24:53;;2430:61:31;;2720:27;;;:::i;:::-;2501:54;;2572:17;2410:112:23;2572:17:31;;2410:112:23;2572:17:31;2501:54;2410:112:23;;2535:11:31;2410:112:23;;;;;1009:32:57;2528:27:31;:::o;2430:61::-;2455:36;2410:112:23;2455:36:31;:::o;2410:112:23:-;;;;;;;:::i;:::-;;;;-1:-1:-1;2410:112:23;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::o;2058:249:31:-;2410:112:23;;:::i;:::-;1084:24:53;;;2134:50:31;;2720:27;;;:::i;:::-;2194:72;;2283:17;-1:-1:-1;2283:17:31;;-1:-1:-1;2283:17:31;2194:72;-1:-1:-1;2410:112:23;2239:10:31;2410:112:23;;;-1:-1:-1;2410:112:23;;;-1:-1:-1;2410:112:23;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;2228:38:31;2410:112:23;;;;;;;:::i;:::-;;;2228:38:31;;;;:::i;2410:112:23:-;-1:-1:-1;2410:112:23;;;;;;-1:-1:-1;;;2410:112:23;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;-1:-1:-1;2410:112:23;;;;2134:50:31;2166:18;;;:::i;6593:1926:22:-;;602:16:62;;;7053:6:22;7044;7017:24;;416:10:25;;6998:61:22;;6994:84;;7701:47;6866:732;7701:47;:::i;:::-;7776:15;;;;;;;;;:::i;:::-;8009:13;7975:59;8009:13;;;;:::i;:::-;7975:59;;;:::i;:::-;:232;;;;;6866:732;8274:8;;;;8270:40;;416:10:25;8407:70:22;8341:23;;;;:::i;:::-;8387:8;;;:::i;:::-;2410:112:23;1756:61:57;416:10:25;;;;:::i;:::-;8407:70:22;;:::i;:::-;2410:112:23;6593:1926:22;:::o;8270:40::-;8284:26;;;;2410:112:23;8284:26:22;:::o;7975:232::-;8139:68;8178:17;;;;;:::i;:::-;8139:68;;:::i;:::-;7975:232;;;;;6994:84;7061:17;;;2410:112:23;7061:17:22;:::o;6866:732::-;7336:33;;;;;:::i;:::-;7332:266;;6866:732;7701:47;6866:732;7701:47;:::i;7332:266::-;7393:51;:18;;;:::i;:51::-;;;;2410:112:23;7468:24:22;:::o;7389:195::-;2410:112:23;7539:26:22;:::o;2410:112:23:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;1530:1:3;2410:112:23;;:::o;411:102:21:-;467:4;445:10;:27;441:54;;2410:112:23;;;;;;;;;;1273:17:53;2410:112:23;;:::i;:::-;1258:32:53;:89;;;411:102:21;896:51:31;;1081:24;;976:10;;;:::i;:::-;2410:112:23;;;;1018:15:31;;;;;;;;:::i;:::-;;-1:-1:-1;;1018:15:31;;;;;;:::i;:::-;996:19;;2410:112:23;;1623:10:31;2410:112:23;;;;;;;996:19:31;2410:112:23;:::i;:::-;1043:22:31;;;:::i;:::-;;2410:112:23;;1081:24:31;;;;;:::i;:::-;;;;411:102:21:o;896:51:31:-;924:23;-1:-1:-1;924:23:31;;-1:-1:-1;924:23:31;1258:89:53;1305:13;;;;;2410:112:23;1294:36:53;2410:112:23;;467:4:21;1305:13:53;467:4:21;;1294:36:53;;;;;;;:::i;:::-;2410:112:23;1294:53:53;1258:89;;2410:112:23;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;2410:112:23;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2410:112:23;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;2410:112:23;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3821:156:24;3913:57;3821:156;3946:17;;:::i;3062:331::-;2410:112:23;3274:14:24;;:::i;:::-;2410:112:23;;;;;;;;;;3316:15:24;;3305:81;;;2410:112:23;3333:18:24;2410:112:23;;;;;;;;;;;;;;;;;;3305:81:24;;;;;;:::i;1561:306:30:-;1685:11;;1681:28;;2410:112:23;2493:4:30;2410:112:23;;2477:21:30;2473:51;;2628:10;706:157:60;;;;;;;1075:77;2683:25:30;;;;2679:57;;2779:36;;-1:-1:-1;;2410:112:23;2779:36:30;;2775:452;;1561:306;2410:112:23;;;3283:42:30;2410:112:23;3283:42:30;;;;;;;;;:::i;:::-;;3339:8;3335:68;;2410:112:23;;;;;1778:61:30;2410:112:23;2493:4:30;1778:61;;1758:4;1561:306;:::o;3335:68::-;3370:22;2410:112:23;3370:22:30;;2410:112:23;3370:22:30;2775:452;3037:12;2410:112:23;;2628:10:30;3037:12;:::i;:::-;2775:452;;;;2679:57;2717:19;2410:112:23;2717:19:30;;2410:112:23;2717:19:30;2473:51;2507:17;2410:112:23;2507:17:30;;2410:112:23;2507:17:30;1681:28;1698:11;;;1705:4;1698:11;:::o;1237:289::-;;;2410:112:23;1332:4:30;1352:11;;1348:28;;2410:112:23;2493:4:30;2410:112:23;;2477:21:30;2473:51;;2658:10;2410:112:23;;;;2642:15:30;2410:112:23;;;;;;2683:25:30;;;2679:57;;-1:-1:-1;;2779:36:30;;2775:452;;1237:289;2410:112:23;;;3283:42:30;;;;;;;;;;;:::i;:::-;;3339:8;3335:68;;2410:112:23;;;;;;1446:52:30;2410:112:23;2493:4:30;1446:52;;1515:4;1237:289;:::o;3335:68::-;3370:22;;;;;;2775:452;2410:112:23;;;;;;;2961:256:30;2410:112:23;2658:10:30;;3089:27;2658:10;2410:112:23;;;;2642:15:30;2410:112:23;;;;;;;3089:27:30;2410:112:23;;;;;;2658:10:30;;3154:48;;2410:112:23;;3154:48:30;2775:452;;;1348:28;1365:11;;;;1372:4;1365:11;:::o;2431:597:24:-;2410:112:23;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;2943:11:24;2410:112:23;2809:41:24;;2410:112:23;;2870:13:24;;2921:4;;;;419:3:56;2410:112:23;;;;2960:21:24;2410:112:23;399:50:56;2410:112:23;;;;;;:::i;:::-;-1:-1:-1;2410:112:23;;;;;;;;2431:597:24;:::o;1128:211:26:-;1222:18;2410:112:23;321:8:51;934:41;;:46;321:8;;2410:112:23;;1128:211:26;:::o;1257:75::-;;284:42:59;1128:211:26;:::o;2663:231:22:-;2755:22;:10;:22;:::i;:::-;2792:27;;;:::i;:::-;2791:28;2787:55;;2879:7;;;:::i;2410:112:23:-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;2410:112:23;;;;:::o;:::-;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;:::i;:::-;;;;;;;:::o;:::-;;;-1:-1:-1;2410:112:23;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;3427:360:24:-;3717:11;2410:112:23;419:3:56;2410:112:23;;;;3734:21:24;2410:112:23;399:50:56;2410:112:23;;3524:246:24;;;2410:112:23;988:66:24;2410:112:23;;3586:15:24;2410:112:23;988:66:24;;2410:112:23;3619:18:24;988:66;;;2410:112:23;3655:13:24;988:66;;;2410:112:23;3694:4:24;988:66;;;2410:112:23;988:66:24;;;2410:112:23;988:66:24;3524:246;;;;;;:::i;:::-;2410:112:23;3501:279:24;;3427:360;:::o;1579:906:12:-;1757:663;;;;;;;;;;;;;;;;;1372:120;1757:663;1372:120;;;;1757:663;;;;;;1422:151:53;2410:112:23;;:::i;:::-;;;;1558:4:53;1539:25;;;2410:112:23;1539:25:53;;;;2410:112:23;1539:25:53;;:::i;:::-;2410:112:23;;;;;;:::i;:::-;1509:17:53;2410:112:23;;1539:25:53;1495:71;;2410:112:23;1422:151:53;:::o;848:136:62:-;;954:2;939:17;;:38;;;;;932:45;848:136;:::o;939:38::-;975:2;960:17;;;848:136;:::o;2410:112:23:-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::i;2092:1256:53:-;;;2231:17;2410:112:23;;;;;:::i;:::-;;;;:::i;:::-;2216:32:53;2231:17;;2281:42;2410:112:23;2281:42:53;;;;:::i;:::-;2410:112:23;;2347:20:53;;;:77;;2410:112:23;2212:1130:53;2092:1256::o;2347:77::-;2388:36;2399:13;2378:46;2399:13;;;;2410:112:23;;;2388:36:53;;;;;;:::i;:::-;2410:112:23;;;;2378:46:53;;2410:112:23;:::o;2212:1130:53:-;2410:112:23;;;;;:::i;:::-;;;;:::i;:::-;2445:27:53;;2773:28;2571:13;2696:41;2560:45;2571:13;2761:53;2571:13;;;;2410:112:23;;;2560:45:53;;;;;;:::i;:::-;2696:41;;;;;;;:::i;:::-;2773:28;;;;:::i;:::-;2761:53;:::i;2441:901::-;2850:20;2410:112:23;;;;;:::i;:::-;;;;:::i;:::-;2835:35:53;2850:20;;3216:17;;3118:46;2958:45;2969:13;3188:97;2969:13;;;;2410:112:23;;;2958:45:53;;;;;;:::i;:::-;3118:46;;;;;;;:::i;:::-;2410:112:23;;;3216:17:53;;;2969:13;3216:17;;2410:112:23;;;;;;;;3216:17:53;3188:97;:::i;2831:511::-;3316:15;;;;2410:112:23;2831:511:53;2410:112:23:o;2236:538:62:-;;;2424:69;;2514:19;;;;;:::i;:::-;2502:31;;;2554:19;2891:941:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;2543:30:62;;2583:185;;;;2236:538::o;2583:185::-;;;;;;;1790:986:28;;;;;;3536:15:62;;;;:::i;:::-;3561:150;;;3743:15;3561:150;;;;;;;;;3743:15;;:::i;:::-;1409:60:28;;;;;3445:249:7;3326:374;3445:249;;;;;;;;;;;;;;;3326:374;;1409:60:28;1401:68;2154:90;;2318:35;;;:::i;:::-;2497:31;;;;;;;;:66;;;;1790:986;2493:84;;2410:112:23;552:216:61;2410:112:23;2734:35:28;2410:112:23;;1691:97:61;2410:112:23;1897:146:50;2410:112:23;;;;:::i;:::-;;;;;:::i;:::-;3561:150:62;2410:112:23;552:216:61;;;2410:112:23;;3561:150:62;552:216:61;;2410:112:23;;;;;;;;;:::i;:::-;;;;;3561:150:62;2410:112:23;;;;3561:150:62;2410:112:23;;;;;;:::i;552:216:61:-;2410:112:23;1097:65:61;;2410:112:23;;3561:150:62;2410:112:23;1691:97:61;;;3561:150:62;1691:97:61;;2410:112:23;;;3561:150:62;2410:112:23;;;;;;;;:::i;1691:97:61:-;2410:112:23;1572:226:61;;1897:146:50;3445:249:7;3326:374;3445:249;;;;;;;;;;;;;;;3326:374;;1897:146:50;2734:35:28;;:::i;2493:84::-;2565:12;;;;;;;;;;2410:112:23;2565:12:28;:::o;2497:66::-;2532:31;;;2497:66;;2154:90;2232:12;;;;;;;;2410:112:23;2232:12:28;:::o;2863:283::-;;3065:74;2863:283;;;1054:77:50;2863:283:28;2410:112:23;;;;;;;;;;:::i;:::-;;;;;;;;320:29:55;2410:112:23;;;949:43:55;2410:112:23;949:43:55;;2410:112:23;;;320:29:55;;;2410:112:23;949:43:55;;;;;;:::i;2816:191:31:-;2915:20;2816:191;2915:20;:::i;:::-;2945:55;;;2816:191;:::o;2945:55::-;676:1:26;2967:33:31;;;;676:1:26;2967:33:31;2410:112:23;;2967:33:31;;1042:6:52;;2410:112:23;;;;1042:6:52;;;;:::o;:::-;;;;;;;;;;;;:::i;:::-;;;;;;2410:112:23;;1042:6:52;;;2410:112:23;1042:6:52;;;;;;;;:::i;:::-;2410:112:23;;1042:6:52;;;;;;;2508:429;;;;;2410:112:23;1420:29:52;;2657:274;;2508:429;;;;;:::o;2657:274::-;2757:53;2410:112:23;;2757:53:52;2410:112:23;;;2757:53:52;;;;;;;2410:112:23;2757:53:52;;1042:6;2757:53;;;:::i;:::-;;2410:112:23;;2757:53:52;;;;;;;2410:112:23;2757:53:52;2410:112:23;2757:53:52;-1:-1:-1;2757:53:52;;;2657:274;2410:112:23;;2828:62:52;2824:96;;2657:274;;;;;;2824:96;2899:21;-1:-1:-1;2899:21:52;1042:6;-1:-1:-1;2899:21:52;2757:53;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;:::i;972:6::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;2410:112:23;972:6:52;2410:112:23;972:6:52;;-1:-1:-1;;972:6:52;2410:112:23;;;;;;;-1:-1:-1;2410:112:23;;;;;;;;972:6:52;;;:::o;:::-;;;;;;;;;2410:112:23;;972:6:52;;;;;;;;;2410:112:23;;;:::i;:::-;;;;;;972:6:52;;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;2410:112:23;972:6:52;;;2410:112:23;972:6:52;;;;;;;;:::i;1717:550::-;;;;;2410:112:23;1420:29:52;;1963:298;;1717:550;;;;;;;:::o;1963:298::-;2063:79;2410:112:23;2063:79:52;2410:112:23;;;;2063:79:52;;;;;;;2410:112:23;2063:79:52;;;;;;:::i;:::-;;2410:112:23;;2063:79:52;;;;;;;2410:112:23;2063:79:52;2410:112:23;2063:79:52;-1:-1:-1;2063:79:52;;;1963:298;2410:112:23;;2160:60:52;2156:94;;1963:298;;;;;;;;2063:79;;;;;;;;;;;;;;:::i;:::-;;;;1229:200:60;706:157;;-1:-1:-1;706:157:60;;-1:-1:-1;706:157:60;1347:76;1229:200::o;7668:995:15:-;7790:14;2720:9:31;31914:149:15;;;;;;;;31787:282;;7790:14;7857:800;;;;;;;;;7668:995;7857:800;;;;;;;;2410:112:23;7857:800:15;;2410:112:23;7857:800:15;;;;;7668:995::o;7857:800::-;;;;;;;;;;;;;;;;;;;;;;;;;2410:112:23;7857:800:15;7668:995::o;7857:800::-;;;;7668:995::o;7857:800::-;;;-1:-1:-1;7857:800:15;;785:146:53;2410:112:23;;;;;;;;;908:13:53;;;;2410:112:23;;;;898:24:53;2410:112:23;;874:49:53;2410:112:23;908:13:53;874:49;;2410:112:23;;;:::i;:::-;;;;;;874:49:53;;;;;;:::i;12055:2121:15:-;;2410:112:23;12167:14:15;;1043:9:31;31914:149:15;;;;;;;;31787:282;;12167:14;12234:1936;;;;;;;;;;12055:2121;12234:1936;;;;;;;;;;;;;;;2410:112:23;12234:1936:15;;2410:112:23;12234:1936:15;;;;;;;;;;;;12055:2121::o;12234:1936::-;;;;;;;;;;;;;;;;;;;;;;;;;;;12055:2121::o;12234:1936::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2410:112:23;12234:1936:15;;;2410:112:23;12234:1936:15;;2410:112:23;12234:1936:15;;;2410:112:23;12234:1936:15;;2410:112:23;12234:1936:15;;;2410:112:23;12234:1936:15;;;;;;;;;;;;;;;;;;;12055:2121::o;12234:1936::-;;;;;;12055:2121::o;12234:1936::-;;;;;;;;;;;;12055:2121::o;12234:1936::-;-1:-1:-1;12234:1936:15;-1:-1:-1;12234:1936:15;;-1:-1:-1;12055:2121:15:o;12234:1936::-;;;;;8608:577:22;8715:1;8748:3;8722:17;;2410:112:23;;8718:28:22;;;;;8814:20;;;;:::i;:::-;;2410:112:23;;;;;;;9483:4:22;;9450:49;;9530:23;;;:::i;:::-;2410:112:23;1222:74:57;;;;;1554:26:31;9930:42:22;;;9450:49;9926:92;;1756:61:57;;8715:1:22;1756:61:57;2410:112:23;10293:17:22;1756:61:57;;10138:11:22;;;;2410:112:23;10100:62:22;10151:10;2410:112:23;;10151:10:22;;;;;10100:62;;;;;:::i;:::-;2410:112:23;;10221:10:22;;10193:39;10138:11;10193:39;;;;;;;;;;;:::i;:::-;10293:17;;;;:::i;:::-;9093:8;:39;;;9450:49;9089:79;;8748:3;2410:112:23;;8703:13:22;;9089:79;9141:27;2410:112:23;10151:10:22;2410:112:23;9141:27:22;;;;;;;;;;:::i;:::-;;;;9093:39;-1:-1:-1;10138:11:22;9105:27;;2410:112:23;;;9093:39:22;;9926:92;9981:37;8715:1;9981:37;;8715:1;9981:37;9930:42;9967:4;;2410:112:23;;;9953:19:22;9930:42;;9450:49;;;;1716:220:53;2410:112:23;;1815:4:53;1797:23;;1793:49;;1859:70;2410:112:23;;;1908:18:53;;;;2410:112:23;1908:18:53;;;;2410:112:23;1908:18:53;;:::i;:::-;2410:112:23;;;;;;:::i;:::-;1509:17:53;2410:112:23;;1908:18:53;1864:64;;2410:112:23;1859:70:53;:::i;1793:49::-;1822:20;2410:112:23;1822:20:53;:::o;3097:266:31:-;1084:24:53;;3181:36:31;;2720:27;;;:::i;:::-;3231:22;3227:40;;2410:112:23;;3297:11:31;2410:112:23;;3297:32:31;2410:112:23;;;1009:32:57;3297::31;:::i;:::-;3346:10;;3097:266;:::o;3181:36::-;3206:11;3213:4;3206:11;:::o;2410:112:23:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;1264:145:54:-;536:66;1347:20;;:55;;;;;1340:62;1264:145;:::o;1347:55::-;651:66;1371:31;;;1264:145;:::o;5002:655:15:-;31914:149;;;1994:9:31;-1:-1:-1;31914:149:15;;-1:-1:-1;31914:149:15;5177:474;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5002:655;;;:::o;5177:474::-;;;;;;;;;;;;;;;;;;;;;;;5002:655::o;5177:474::-;;;5002:655;:::o;5177:474::-;;;5002:655;;:::o;2132:21:20:-;;7261:2;2132:21;;;;;;;:::o;:::-;;2566:1:3;2132:21:20;;;;;;;:::o;:::-;;;;;;;;;;:::o;2643:34::-;2410:112:23;;;2643:34:20;2410:112:23;;2643:34:20;;;2410:112:23;;;;;2643:34:20;:::o;:::-;;;;;;2410:112:23;;2643:34:20;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;2410:112:23;;7178:27:20;2643:34;;;;;;;:::o;1986:4::-;;;;;;;:::i;:::-;2410:112:23;;;1986:4:20;;:::o;2396:14::-;;;;;;;;;2410:112:23;2396:14:20;:::o;6711:2934::-;;;;6894:14;;;2410:112:23;;;416:10:25;-1:-1:-1;6890:125:20;;7178:27;;;;2643:34;27834:42:17;7178:27:20;;7212:22;;;2410:112:23;7236:27:20;;;:::i;:::-;27834:42:17;;:::i;:::-;7178:27:20;2410:112:23;;;;7278:23:20;:46;7274:89;;7547:27;7516:64;7547:27;;:::i;:::-;7516:64;:::i;:::-;27834:42:17;7635:27:20;;7669;;;2410:112:23;7698:54:20;2410:112:23;;7698:54:20;;:::i;27834:42:17:-;7178:27:20;2410:112:23;;;;7767:33:20;2410:112:23;7178:27:20;2410:112:23;;;;7804:28:20;7767:65;7763:108;;2643:34;7987:30;:34;;:30;;:34;:::i;:::-;2643;2410:112:23;;;2643:34:20;7987;:56;:79;7983:122;;-1:-1:-1;1986:4:20;7178:27;8265:137;8563:27;7669;2410:112:23;1986:4:20;;;;;:::i;:::-;8550:42;;;;;;;;7178:27;-1:-1:-1;1986:4:20;8550:42;;8778:68;8795:30;;8778:68;7669:27;2410:112:23;8778:68:20;;;;;;;:::i;:::-;7669:27;2410:112:23;1986:4:20;;;;;:::i;:::-;8771:76;;8550:42;8771:76;;;;;8901:14;-1:-1:-1;8771:76:20;8901:14;;2410:112:23;-1:-1:-1;2410:112:23;;;;8877:61:20;2410:112:23;;8877:61:20;2410:112:23;7669:27:20;2410:112:23;8877:61:20;;;7178:27;8877:61;;;;;1986:4;;;;;;;;;;;;2410:112:23;;;1986:4:20;;;2410:112:23;1986:4:20;;;2410:112:23;1986:4:20;;;2410:112:23;1986:4:20;2410:112:23;1986:4:20;8877:61;9030:26;;2404:5;9030:26;;;;;:::i;:::-;2410:112:23;;9491:16:20;;;;6711:2934;9487:60;;2410:112:23;9565:73:20;2410:112:23;;;;;9565:73:20;;:::i;9487:60::-;1776:4;;9516:26;;-1:-1:-1;9516:26:20;;7178:27;9516:26;;;;-1:-1:-1;9516:26:20;;-1:-1:-1;9516:26:20;;-1:-1:-1;;9516:26:20:i;9491:16::-;9463:14;;;;9491:16;;7983:122;8082:12;;;;;2410:112:23;8082:12:20;:::o;7274:89::-;7340:12;;;;;;2410:112:23;7340:12:20;:::o;26453:299:14:-;26570:176;;;;;;;;;;;;;;;26453:299::o;26570:176::-;;3037:251:8;;;;;3180:33;;;;;;;:::i;:::-;3230:51;;;;;;;;;;;3037:251;:::o;3230:51::-;3250:31;;;;:::i;9664:1284:13:-;9852:1090;;;2410:112:23;;9664:1284:13;9852:1090;;9664:1284;9852:1090;;;;;;;;;;;9664:1284::o;9852:1090::-;;;;;;;;;;2410:112:23;9852:1090:13;;;;;;2410:112:23;9852:1090:13;;;;2410:112:23;9852:1090:13;;;;2410:112:23;9852:1090:13;;;;;;;;;9664:1284::o;9852:1090::-;;;;;;;;;;;;;;;;;;;;;;;;;;;2756:1082:49;;;2891:941;;;;;;;;;;;;;;;;;;;;;;;;;;;2756:1082::o;2410:112:23:-;;-1:-1:-1;;2410:112:23;;;;;;;:::o;:::-;2162:66:19;2410:112:23;;2162:66:19;2410:112:23;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;2410:112:23;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;2424:1898:50:-;;2663:18;2659:1392;;2424:1898;4132:184;;-1:-1:-1;4132:184:50;-1:-1:-1;4132:184:50;-1:-1:-1;4132:184:50;-1:-1:-1;2424:1898:50;:::o;2659:1392::-;2410:112:23;;2739:25:50;;2746:17;;;:::i;:::-;2739:25;;;:::i;:::-;;2410:112:23;;;;2739:25:50;2410:112:23;2739:40:50;2410:112:23;;-1:-1:-1;2911:17:50;;;;;;2891:560;2735:1316;;;;2659:1392;;;;2930:3;2970:9;;;;;;:::i;:::-;2410:112:23;;;;3001:22:50;2410:112:23;;3112:6:50;;;3108:17;;3222:10;;;;;:::i;:::-;3207:42;;;;;;:::o;3108:17::-;3120:5;;2997:440;3278:25;;;:::i;:::-;3274:163;;2762:1;2410:112:23;2896:13:50;;2735:1316;3577:25;;3572:469;3604:5;;;3572:469;2735:1316;;;;;3611:3;3651:13;;3658:5;;;;;;;:::i;:::-;3651:13;;;:::i;:::-;2410:112:23;;;;3686:22:50;2410:112:23;;3807:10:50;;;;3827;3807;;;;:::i;:::-;3827;;;;:::i;:::-;3792:47;;;;;:::o;3682:345::-;3868:25;;;;;;;:::i;:::-;3864:163;;3611:3;3682:345;3611:3;:::i;:::-;3577:25;;;3864:163;4003:5;;2078:238:57;1498:77;;676:1:26;1498:77:57;;2234:9;;2230:32;;2287:15;2280:22;;2272:37;2078:238;:::o;2230:32::-;-1:-1:-1;;;;;2245:17:57:o;1597:227:33:-;2410:112:23;1681:2:33;2410:112:23;-1:-1:-1;2410:112:23;1736:19:33;2410:112:23;;1681:2:33;-1:-1:-1;2410:112:23;;;;-1:-1:-1;;2410:112:23;;;;;;;;;;;;1736:33:33;1730:88;;1597:227::o;1380:433:62:-;;;2891:941:49;;;;;;;;;;;;;;;;;;;;;;;;;;1593:19:62;1622:185;1541:31;;;1593:19;;:::i;:::-;1582:30;;;1622:185;;;;1380:433::o;1059:443:58:-;2410:112:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;966:35:58;1263:29;1189:296;1263:36;:29;;:36;:::i;:::-;1189:296;2410:112:23;1317:23:58;;2410:112:23;1358:25:58;2410:112:23;1358:25:58;;966:35;1401:26;2410:112:23;;;1401:26:58;;2410:112:23;;;;;;1445:26:58;;2410:112:23;;;;1189:296:58;;;2410:112:23;1189:296:58;;;;966:35;;;;2410:112:23;966:35:58;;;;;;;;;2410:112:23;;;966:35:58;;;2410:112:23;966:35:58;;;2410:112:23;966:35:58;;;2410:112:23;;966:35:58;;;2410:112:23;966:35:58;2410:112:23;966:35:58;3045:424:52;;;;;2410:112:23;1420:29:52;;3193:270;;3045:424;;;;:::o;3193:270::-;3291:52;2410:112:23;;3291:52:52;2410:112:23;;;3291:52:52;;;;;;;2410:112:23;3291:52:52;;;;;;:::i;:::-;;2410:112:23;;3291:52:52;;;;;;;2410:112:23;3291:52:52;2410:112:23;3291:52:52;-1:-1:-1;3291:52:52;;;2410:112:23;;3361:61:52;3357:95;;3193:270;;;;;;985:132:3;2410:112:23;;1078:32:3;;2410:112:23;;;;:::i;:::-;;;;;;;;;;;;;;1078:32:3;:::i;1562:703:18:-;;;;;;1691:6;;:32;;;;1562:703;1691:42;;;;1562:703;1691:68;;;;1562:703;1687:111;;1821:39;;;;:::i;:::-;1820:40;1816:83;;3235:647:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3235:647:19;;;;;;2222:3:18;3235:647:19;;2132:64:18;3235:647:19;;2062:34:18;;;;1984:49;;2132:64;;:::i;:::-;2222:3;;:::i;:::-;2211:18;;2251:7;1562:703;:::o;1691:68::-;1737:22;2162:66:19;1737:22:18;;;1691:68;;:42;1727:6;;;1691:42;;:32;1701:22;2162:66:19;1701:22:18;;;1691:32;;2410:112:23;;;;;;;;;;;;;:::i;4036:591:8:-;;;;4229:25;4230:24;;;;:::i;4229:25::-;:54;;;;4036:591;4225:176;;4453:54;2410:112:23;4479:27:8;;2410:112:23;;;;;4479:27:8;;;;;;;;1986:4:20;;;;;;;;;;;;2410:112:23;;;1986:4:20;;;2410:112:23;1986:4:20;;;2410:112:23;1986:4:20;;;2410:112:23;1986:4:20;2410:112:23;1986:4:20;4479:27:8;4453:54;;4461:5;4453:54;;;;:::i;:::-;4525:36;;;;4036:591;4524:96;;;2410:112:23;4479:27:8;2410:112:23;4566:30:8;2410:112:23;;4566:30:8;;;;;;:::i;:::-;4524:96;4598:4;4036:591;:::o;4524:96::-;;4453:54;4524:96;4453:54;4036:591;:::o;4525:36::-;2410:112:23;4479:27:8;2410:112:23;;4536:25:8;4525:36;;4225:176;4299:20;;;;;4307:5;4299:20;4314:4;4299:20;:::o;4229:54::-;4259:24;4258:25;4259:24;;;;:::i;4258:25::-;4229:54;;4725:553;;;;;;4850:24;;;;:::i;:::-;4849:25;2410:112:23;;4849:54:8;;4725:553;4845:97;;2162:66:19;12713:24:9;5250:5:8;2410:112:23;16679:38:8;5203:28;2410:112:23;;;:::i;:::-;;;;:::i;:::-;;;;;15616:15:8;;;2410:112:23;;15616:15:8;;;2410:112:23;15601:30:8;;2410:112:23;;:::i;:::-;;;;15616:15:8;15663:17;;2410:112:23;15678:1:8;15616:15;15663:17;;2410:112:23;15648:32:8;;2410:112:23;;;;15648:32:8;;;;2410:112:23;;:::i;:::-;1938:66:19;2410:112:23;;2032:66:19;15616:15:8;15716:17;;2410:112:23;15678:1:8;15616:15;15716:17;;2410:112:23;;;;15701:32:8;;;16601:38;15769:27;15783:12;;15769:27;:::i;:::-;2410:112:23;;;15754:42:8;;;16524:38;16442;15833:27;15847:12;;15833:27;:::i;:::-;2410:112:23;;;15818:42:8;;;15897:38;15908:12;;15922;;15897:38;;:::i;:::-;15882:53;2410:112:23;;;15882:53:8;;;15990:12;15964:53;15979:38;15990:12;;16004;;15979:38;;:::i;:::-;15964:53;2410:112:23;;;;15964:53:8;;16066:12;16040:53;16055:38;16066:12;;16080;;16055:38;;:::i;:::-;16040:53;2410:112:23;;;;16040:53:8;;16143:12;16117:53;16132:38;16143:12;;16157;;16132:38;;:::i;:::-;16117:53;2410:112:23;;;;16117:53:8;;16220:12;16194:53;16209:38;16220:12;;16234;;16209:38;;:::i;:::-;16194:53;2410:112:23;;;;16194:53:8;;16297:12;16271:53;16286:38;16297:12;;16311;;16286:38;;:::i;:::-;16271:53;2410:112:23;;;;16271:53:8;;16375:12;16349:53;16364:38;16375:12;;16389;;16364:38;;:::i;:::-;16349:53;2410:112:23;;;;16349:53:8;;16453:12;16467;;16442:38;;:::i;:::-;2410:112:23;;;16427:53:8;;;16535:12;;16524:38;:::i;:::-;2410:112:23;;;16509:53:8;16612:12;16626;;16601:38;;:::i;:::-;2410:112:23;;;16586:53:8;2410:112:23;16679:38:8;2410:112:23;;;16664:53:8;12713:24:9;:::i;:::-;5153::8;;;;5106;;5203:28;;:::i;:::-;5250:5;2162:66:19;1698::8;;;;4849:54;4879:24;;;;;:::i;:::-;4878:25;4849:54;;1404:1074:49;;;1535:937;;;;;;;;;;;;;;;;;;;;;;;;;1404:1074::o;1535:937::-;;;;2410:112:23;;1535:937:49;1404:1074::o;:::-;;;1535:937;;;;;;;;;;;;;;;;;;;;;;;;;;;1404:1074::o;4583:195:50:-;2410:112:23;;4667:12:50;;:35;;;;;4583:195;4667:58;;;;4583:195;4667:81;;;;4583:195;4667:104;;;;4660:111;4583:195;:::o;4667:104::-;2410:112:23;4752:19:50;;;4583:195;:::o;4667:81::-;2410:112:23;4729:19:50;;;-1:-1:-1;4667:81:50;;:58;2410:112:23;4706:19:50;;;-1:-1:-1;4667:58:50;;:35;2410:112:23;4683:19:50;;;-1:-1:-1;4667:35:50;;1102:6:52;;;;;;;;;;;1042;;;:::i;:::-;1102;;;;;;;;;;;;;;:::i;3695:483::-;2410:112:23;;3695:483:52;;;;;2410:112:23;1420:29:52;;3879:293;;3695:483;;;;;:::o;3879:293::-;-1:-1:-1;2410:112:23;;;;;;;;1102:6:52;2410:112:23;;;;4016:44:52;;;;;;;2410:112:23;4016:44:52;;;;;2410:112:23;;1102:6:52;;;2410:112:23;1102:6:52;;;2410:112:23;1102:6:52;;;;;;;;;;:::i;:::-;4016:44;2410:112:23;;4016:44:52;;;;;;-1:-1:-1;;;4016:44:52;;;3879:293;3980:80;2410:112:23;;3980:80:52;2410:112:23;;4078:53:52;4074:87;;3879:293;;;;;;;4016:44;2410:112:23;4016:44:52;;2410:112:23;4016:44:52;;;;;;-1:-1:-1;4016:44:52;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;1161:6;;;;;;;2410:112:23;;;;1161:6:52;;;2410:112:23;1161:6:52;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;4373:457::-;;;;2410:112:23;1420:29:52;;4562:262;;4373:457;;;;;:::o;4562:262::-;4651:62;2410:112:23;4651:62:52;2410:112:23;4651:62:52;2410:112:23;;4651:62:52;;;;;;;2410:112:23;4651:62:52;;;;;;:::i;:::-;;2410:112:23;;4651:62:52;;;;;;;2410:112:23;4651:62:52;2410:112:23;4651:62:52;;;;;4562:262;2410:112:23;;4731:52:52;4727:86;;4562:262;;;;;;;4651:62;;;;;;;;;;;;;;:::i;:::-;;;;654:201:47;2410:112:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;619:28:47;793:17;;;2410:112:23;;;-1:-1:-1;;2410:112:23;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;967:3:48;2410:112:23;;949:16:48;;;;;1007:8;;2410:112:23;1007:8:48;;;:::i;:::-;;2410:112:23;;;;;;;:::i;:::-;;;;;;;;;;;;;;;443:20:48;2410:112:23;;;;;655:10:48;2410:112:23;;655:10:48;;2410:112:23;677:9:48;;;2410:112:23;;;;;667:20:48;2410:112:23;;;620:68:48;2410:112:23;620:68:48;;2410:112:23;;;;443:20:48;;2410:112:23;443:20:48;;;2410:112:23;443:20:48;;;2410:112:23;620:68:48;;;;;;;:::i;:::-;2410:112:23;610:79:48;;990:26;;;;:::i;:::-;2410:112:23;;934:13:48;;949:16;;;;;;759:88:47;949:16:48;;2410:112:23;949:16:48;;2410:112:23;949:16:48;2410:112:23;;1067:24:48;;2410:112:23;1067:24:48;;;2410:112:23;;;:::i;1067:24:48:-;2410:112:23;1057:35:48;;819:27:47;;2410:112:23;;;;;;;;;;759:88:47;;2410:112:23;;;619:28:47;;;2410:112:23;;;;;;619:28:47;;;2410:112:23;;619:28:47;;;759:88;619:28;15690:1115:16;15880:919;;2410:112:23;;15690:1115:16;;;15880:919;;;;;;15690:1115;15880:919;;;;;;15690:1115;15880:919;;;;;;15690:1115;;;:::o;15880:919::-;;;;-1:-1:-1;15880:919:16;;;;;;-1:-1:-1;;15880:919:16;;;;;;;;;;;;;;;;;;;-1:-1:-1;;15880:919:16;;;;;;;;;;;;;;;;;;;;15690:1115::o;15880:919::-;;;;;;;;-1:-1:-1;15880:919:16;;;2410:112:23;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;2410:112:23;;;;:::i;:::-;;;;;;;;:::o;1186:4022:3:-;;2410:112:23;;1515:16:3;1511:31;;2503:69;2606:24;2547:25;2548:19;:15;2410:112:23;;2548:15:3;:::i;:::-;:19;:::i;:::-;2571:1;416:10:25;;;;2547:25:3;2606:24;:::i;:::-;2641:2537;;;;;;;;;;;;;;;;;1104:5;2641:2537;;;;;;;;;;;;;1186:4022;:::o;2641:2537::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1511:31;2410:112:23;;;;:::i;12684:438:19:-;-1:-1:-1;;;;12774:6:19;;;;:16;;;12684:438;12774:42;;;;12684:438;12770:85;;-1:-1:-1;;;;1802:66:19;12990:15;;;;1666:66;12990:15;;;12966;;;;;12959:29;12952:57;13039:17;12902:15;;;13095:10;12684:438;:::o;12770:85::-;12832:12;;2410:112:23;12832:12:19;:::o;12774:42::-;12796:6;;;12795:20;;12774:42;12795:20;12808:6;;;12774:42;;:16;12784:6;-1:-1:-1;;;;12784:6:19;;;12774:16;;13895:6587;;;2410:112:23;14098:10:19;2410:112:23;14158:19:19;14174:3;14256:13;;;:30;;;13895:6587;14252:44;;14322:25;;;;:::i;:::-;14366:5;;;;;14365:16;;;13895:6587;14362:211;;13895:6587;14586:5830;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;14586:5830:19;;;;;;;;;;;;;;;-1:-1:-1;;14586:5830:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;14586:5830:19;;;;;;;;;-1:-1:-1;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;;13895:6587;:::o;14586:5830::-;-1:-1:-1;;;;14586:5830:19;;;;;;;;;;;;;;-1:-1:-1;;;;14586:5830:19;;;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;;-1:-1:-1;;;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;-1:-1:-1;;;;14586:5830:19;;;;;-1:-1:-1;;;;14586:5830:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;14586:5830:19;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;14586:5830:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;;;-1:-1:-1;;;;14586:5830:19;;;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;;-1:-1:-1;;;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;;;14586:5830:19;;;-1:-1:-1;;14586:5830:19;;;;;;-1:-1:-1;14586:5830:19;;;;-1:-1:-1;14586:5830:19;;-1:-1:-1;;;14586:5830:19;-1:-1:-1;14586:5830:19;;;;;;;;;;;;-1:-1:-1;14586:5830:19;;-1:-1:-1;14586:5830:19;;;1938:66;;-1:-1:-1;2032:66:19;;-1:-1:-1;14586:5830:19;;;;;;-1:-1:-1;;14586:5830:19;-1:-1:-1;;;;14586:5830:19;;;;;;;;;;-1:-1:-1;14586:5830:19;;-1:-1:-1;14586:5830:19;;;;;-1:-1:-1;14586:5830:19;;;;-1:-1:-1;14586:5830:19;;;1938:66;;-1:-1:-1;2032:66:19;;-1:-1:-1;14586:5830:19;;;-1:-1:-1;;14586:5830:19;;;;;;;;;;;;;;;;14362:211;2410:112:23;;2162:66:19;2410:112:23;;;;14437:31:19;;14486:10;2410:112:23;14518:13:19;;;:30;;;14362:211;14514:44;14362:211;14514:44;14550:8;;;;;;;;;2410:112:23;14550:8:19;:::o;14518:30::-;;14535:13;14518:30;;14365:16;14375:5;;;14365:16;;14252:44;14288:8;;;;;;;2410:112:23;14288:8:19;:::o;14256:30::-;14273:13;;;14256:30;;7421:176:8;;7516:14;;;:32;;;;7421:176;7516:50;;;;7421:176;7516:74;;;7509:81;7421:176;:::o;7516:74::-;2326:66;7570:20;;;;7421:176;:::o;7516:50::-;7552:14;;;;-1:-1:-1;7516:50:8;;:32;2162:66:19;-1:-1:-1;7534:14:8;-1:-1:-1;7516:32:8;;;6806:437;-1:-1:-1;;;;6900:337:8;;;;;;;;;;;;;;;;;;;;;;;;;6806:437;:::o;2410:112:23:-;;;;;;;:::i;:::-;-1:-1:-1;2410:112:23;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::i;:::-;;-1:-1:-1;2410:112:23;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::o;12915:1456:8:-;13085:1;;12915:1456;13085:1;;;;12915:1456;13085:1;;13186:7;13190:3;13186:7;;;;14336:28;;;;;;;;:::i;13195:3::-;13222:5;13218:132;;13195:3;13507;13494:9;;2410:112:23;;;;13494:9:8;13493:17;13529:3;13516:9;;2410:112:23;;;;13516:9:8;13515:17;13492:41;13972:13;:11;;;;:::i;:::-;;:13;2410:112:23;13968:276:8;;13195:3;14261:8;14287;14261;2410:112:23;14261:8:8;2410:112:23;;;;14261:8:8;14287;2410:112:23;;;;14287:8:8;13195:3;2410:112:23;13171:13:8;;;;13968:276;14018:6;;;;;;;14014:212;14018:6;;;14065:11;;;;;;;:::i;:::-;;2410:112:23;14080:11:8;2410:112:23;14287:8:8;14261;13972:13;14095:11;14080:13;:11;;;;:::i;:::-;;:13;2410:112:23;14095:11:8;;;:::i;:::-;;:13;2410:112:23;14052:57:8;;14014:212;;13968:276;;;;;14014:212;14261:8;14182:11;;2410:112:23;14182:11:8;14176:27;14182:11;;14287:8;14182:11;;;:::i;:::-;;14176:27;:::i;:::-;14164:39;;;;;14014:212;;;13218:132;13263:17;;;;;13314;13263;;;:::i;:::-;13314;;:::i;:::-;13302:29;;;;;13218:132;;;2410:112:23;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;13224:499:19;;;1938:66;2032;13342:11;12535:6;;13437:41;;13492:6;13686:30;13492:6;;;;13491:18;;;13224:499;13488:181;;;9612:681;;-1:-1:-1;;;;9612:681:19;;;;-1:-1:-1;;;;9612:681:19;;;;;;;;;;;;;;;;;;;;13563:1;9612:681;;;;;;;;;;;;;;;;;;;;;13563:1;9612:681;;;;;;;;;;;;;;;;;;;13525:42;13686:30;:::i;13488:181::-;13627:31;;;;;;:::i;:::-;13605:53;;;;13686:30;:::i;13491:18::-;13502:6;;;;13491:18;;13437:41;-1:-1:-1;13463:15:19;-1:-1:-1;13463:15:19;:::o;16956:185:8:-;17079:23;16956:185;2410:112:23;;:::i;:::-;;;;17093:3:8;17098;17093;;;2410:112:23;17098:3:8;;2410:112:23;17079:23:8;;:::i;:::-;2410:112:23;17098:3:8;2410:112:23;;;;;:::i;:::-;;;17093:3:8;17119:15;;2410:112:23;17098:3:8;17119:15;;2410:112:23;16956:185:8;:::o;16745:205::-;16884:27;16745:205;2410:112:23;;:::i;:::-;;;;16906:4:8;16900;;;2410:112:23;16906:4:8;;2410:112:23;16884:27:8;;:::i;13443:255:9:-;2162:66:19;2410:112:23;13567:18:9;13443:255;13567:18;:::i;:::-;13599:8;;13595:74;;13443:255;:::o;13595:74::-;1829:135:5;;;1035:4;1829:135;;;;;11599:781:8;;;;-1:-1:-1;;;;11599:781:8;;11718:656;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11599:781;:::o;8875:2541::-;;;;;;2410:112:23;9016:10:8;2410:112:23;9028:10:8;2410:112:23;9050:2360:8;;;;;;-1:-1:-1;;;;9050:2360:8;;;-1:-1:-1;;;;9050:2360:8;;;;-1:-1:-1;;;;9050:2360:8;;;;;;;;;;-1:-1:-1;;;;9050:2360:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8875:2541;;;;:::o;9050:2360::-;-1:-1:-1;;;;9050:2360:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;9050:2360:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7877:436;;;8002:7;;7998:26;;-1:-1:-1;;;;2410:112:23;13567:18:9;12713:24;13567:18;:::i;:::-;13599:8;;;13595:74;;-1:-1:-1;;;;1531:66:19;;;;;13678:13:9;;8129:178:8;;;;;;;;7877:436;:::o;7998:26::-;8011:13;;;;8008:1;8011:13;8008:1;8011:13;:::o;10559:1073:19:-;;;;10790:7;;10786:67;;-1:-1:-1;;;;10867:673:19;13645:1;10867:673;;;;;;;;;;;;;;;;;;;;;13645:1;10867:673;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13645:1;10867:673;;13645:1;10867:673;10559:1073;:::o;10786:67::-;10817:21;;;;;13645:1;10817:21;13645:1;10817:21;:::o;8954:351::-;;;;;4081:643;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;4081:643:19;;;;;;;;;-1:-1:-1;;4081:643:19;;;;-1:-1:-1;;;;4081:643:19;;;;;;;9135:20;;;9186:21;;9232:17;;9271:20;;8954:351;:::o;14447:1598:9:-;;;14566:6;;14562:29;;14601:1438;;14571:1;14601:1438;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14571:1;14601:1438;14447:1598;:::o;14562:29::-;14574:17;;;14571:1;14574:17;14571:1;14574:17;:::o

Swarm Source

none://164736f6c634300081d000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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