APE Price: $0.76 (+2.02%)

Token

Q00tants (q00tants)

Overview

Max Total Supply

0 q00tants

Holders

5

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
4 q00tants
0x80BfB857770a802f7eF375921AD5E83c76214a2d
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
Q00tantShadow

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, MIT license
File 1 of 13 : Q00tantShadows.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

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

/**
 * @title Q00tantShadow
 */
contract Q00tantShadow is NFTShadow {
    constructor() NFTShadow(0x000000000000F87b8230c9233b00474eda1E1b3b) {
        initialize(
            0xe880c31C8118103aB49B604E281283E489a69780,
            "Q00tants",
            "q00tants",
            "",
            0x7Df5c32827f0Fa448392Ce58231Ce4f378ce56e5,
            address(0),
            0
        );
    }
}

File 2 of 13 : NFTShadow.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ERC721} from "solady/tokens/ERC721.sol";
import {LibString} from "solady/utils/LibString.sol";
import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {ERC2981} from "solady/tokens/ERC2981.sol";

import {IERC5192} from "./interfaces/IERC5192.sol";
import {IBeacon} from "./interfaces/IBeacon.sol";
import {ICreatorToken} from "./interfaces/ICreatorToken.sol";
import {ITransferValidator} from "./interfaces/ITransferValidator.sol";
import {IShadowCallbackReceiver} from "./interfaces/IShadowCallbackReceiver.sol";

/**
 * @title NFTShadow
 * @author @0xQuit
 * @notice A contract for soulbound Shadow NFTs that follow ownership on a remote chain.
 * @notice This contract is designed to be used with a Beacon contract (see IBeacon.sol) to maintain ownership records
 * through LayerZero's lzRead protocol.
 * @notice Soulbound tokens can be unlocked by locking them on their source chain.
 * @notice Contracts have shadow mode disabled by default. In this state, they function very much like a typical oNFT. They
 * can be minted by locking the native asset, and the native asset can be unlocked by burning the Shadow NFT.
 * @notice When tokens are locked, ONLY the Beacon contract can transfer them. They will follow the canonical owner,
 * as resolved by the ExclusiveDelegateResolver (the "Resolver") contract. Users should only issue Resolver compatible
 * delegations for assets if they own the delegatee. Though the delegatee can not claim ownership of the underlying asset,
 * they may be able to claim airdrops, participate in activations, or otherwise interact with the asset using the Shadow NFT.
 */
contract NFTShadow is ERC721, ERC2981, IERC5192, ICreatorToken, OwnableRoles {
    // Only the Beacon contract can perform admin actions when a token is in Shadow mode
    error CallerNotBeacon();

    // ERC-4906 BatchMetadataUpdate event
    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);

    // The token is currently in Shadow mode
    error TokenLocked();

    // The token is not in Shadow mode
    error TokenNotLocked();

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

    // Emitted when a new metadata renderer is set
    event MetadataRendererSet(address indexed metadataRenderer);

    // Emitted when shadow mode is enabled
    event ShadowModeEnabled();

    // The address of the Beacon contract
    address public immutable BEACON_CONTRACT_ADDRESS;

    // Admin management roles
    uint256 public constant SHADOW_MODE_MANAGER_ROLE = _ROLE_13;
    uint256 public constant METADATA_MANAGER_ROLE = _ROLE_42;
    uint256 public constant TRANSFER_VALIDATOR_MANAGER_ROLE = _ROLE_69;
    uint256 public constant ROYALTY_MANAGER_ROLE = _ROLE_88;

    // The address of the ERC721C transfer validator, address(0) for none
    address public transferValidator;

    // Mapping to store callback target for each GUID
    mapping(bytes32 guid => address callbackTarget) public callbacks;

    // _extraData flags to indicate if a token is in Shadow mode (locked) or not (unlocked)
    uint96 private constant LOCKED = 0;
    uint96 private constant UNLOCKED = 1;

    // The base URI for the token metadata
    string private _baseTokenUri;

    // The name of the collection
    string private _name;

    // The symbol of the collection
    string private _symbol;

    // The address of the MetadataRenderer contract (address(0) if not set)
    address public metadataRenderer;

    // If false, the token can only be minted by locking it on the source chain
    bool public shadowModeEnabled;

    /**
     * @param _beaconContract The address of the Beacon contract
     */
    constructor(address _beaconContract) {
        BEACON_CONTRACT_ADDRESS = _beaconContract;
    }

    /// @dev Fallback function for calls from Beacon contract.
    fallback() external {
        _shadowFallback();
    }

    /**
     * @notice Initializes the NFTShadow contract.
     * @param _initialOwner The address of the initial owner.
     * @param _collectionName The name of the collection.
     * @param _collectionSymbol The symbol of the collection.
     * @param _baseTokenURI The base URI for the token metadata.
     * @param _metadataRenderer The address of the MetadataRenderer contract.
     * @param _transferValidator The address of the transfer validator.
     * @param _royaltyFeeNumerator The ERC2981 royalty fee numerator.
     */
    function initialize(
        address _initialOwner,
        string memory _collectionName,
        string memory _collectionSymbol,
        string memory _baseTokenURI, // can be left empty if metadataRenderer is set
        address _metadataRenderer, // address(0) if not set
        address _transferValidator,
        uint96 _royaltyFeeNumerator
    ) public {
        _baseTokenUri = _baseTokenURI;
        _name = _collectionName;
        _symbol = _collectionSymbol;
        metadataRenderer = _metadataRenderer;
        _initializeOwner(_initialOwner);

        transferValidator = _transferValidator;
        _setDefaultRoyalty(_initialOwner, _royaltyFeeNumerator);
    }

    /**
     * @notice Transfers a token from one address to another.
     * @param from The address of the sender.
     * @param to The address of the recipient.
     * @param tokenId The token ID to transfer.
     * @dev If the token is locked, only the Beacon contract can transfer it.
     * @dev If the token is unlocked, only the owner or approved address can transfer it.
     */
    function transferFrom(address from, address to, uint256 tokenId) public payable override {
        if (msg.sender == BEACON_CONTRACT_ADDRESS) {
            if (_getExtraData(tokenId) == UNLOCKED) revert TokenNotLocked();

            _transfer(address(0), from, to, tokenId);
        } else {
            super.transferFrom(from, to, tokenId);
        }
    }

    /**
     * @notice Triggers an ownership update for the tokens.
     * @param tokenIds The token IDs to update ownership for.
     * @param eids The EIDs to read ownership from. If token is locked on the provided EID, no update will occur.
     */
    function read(uint256[] calldata tokenIds, uint32[] calldata eids) public payable returns (bytes32) {
        return _read(tokenIds, eids, 0);
    }

    /**
     * @notice Triggers an ownership update with custom options. Helpful if a component of the update or callback is particularly expensive.
     * @param tokenIds The token IDs to update ownership for.
     * @param eids The EIDs to read ownership from. If token is locked on the provided EID, no update will occur.
     * @param callbackGasLimit The gas limit for the callback.
     * @return guid The GUID of the callback.
     * @dev Any excess fees provided to LayerZero will be returned to the caller. Potential callers are responsible for ensuring
     * that they are able to receive native tokens.
     */
    function readWithCallback(uint256[] calldata tokenIds, uint32[] calldata eids, uint128 callbackGasLimit)
        external
        payable
        returns (bytes32)
    {
        bytes32 guid = _read(tokenIds, eids, callbackGasLimit);

        callbacks[guid] = msg.sender;

        return guid;
    }

    /**
     * @notice Unlocks and sends tokens to the beneficiary on the specified EID.
     * @param dstEid The EID to unlock and send the tokens on.
     * @param tokenIds The token IDs to unlock and send.
     * @param beneficiary The address of the recipient on the target chain.
     * @param refundRecipient The address to refund the native fee to.
     * @param supplementalGasLimit The gas limit for the callback.
     * @dev Must be owner or approved, and the token must be unlocked (not in Shadow mode). Tokens released on the target chain will be locked on this chain.
     */
    function send(
        uint32 dstEid,
        uint256[] calldata tokenIds,
        address beneficiary,
        address refundRecipient,
        uint128 supplementalGasLimit
    ) external payable {
        for (uint256 i = 0; i < tokenIds.length; i++) {
            if (!_isApprovedOrOwner(msg.sender, tokenIds[i])) revert NotOwnerNorApproved();
            if (_locked(tokenIds[i])) revert TokenLocked();

            if (!shadowModeEnabled) {
                _burn(tokenIds[i]);
            }

            _setExtraData(tokenIds[i], LOCKED);

            emit Locked(tokenIds[i]);
        }

        address baseCollectionAddress = IBeacon(BEACON_CONTRACT_ADDRESS).shadowToBase(address(this));
        IBeacon(BEACON_CONTRACT_ADDRESS).send{value: msg.value}(
            dstEid, baseCollectionAddress, tokenIds, beneficiary, refundRecipient, supplementalGasLimit
        );
    }

    /**
     * @notice Enables shadow mode for the token.
     * @dev If shadow mode is enabled, shadows can be minted by the Beacon contract.
     * @dev Once enabled, shadow mode cannot be disabled.
     */
    function enableShadowMode() external onlyRoles(SHADOW_MODE_MANAGER_ROLE) {
        shadowModeEnabled = true;
    }

    /**
     * @notice Sets the base URI for the token metadata.
     * @param uri The base URI for the token metadata.
     * emits BatchMetadataUpdate event
     */
    function setTokenURI(string memory uri) external onlyRoles(METADATA_MANAGER_ROLE) {
        _baseTokenUri = uri;

        emit BatchMetadataUpdate(0, type(uint256).max);
    }

    /**
     * @notice Sets the metadata renderer for the collection.
     * @param _metadataRenderer The address of the metadata renderer.
     */
    function setMetadataRenderer(address _metadataRenderer) external onlyRoles(METADATA_MANAGER_ROLE) {
        metadataRenderer = _metadataRenderer;

        emit MetadataRendererSet(_metadataRenderer);
        emit BatchMetadataUpdate(0, type(uint256).max);
    }

    /**
     * @notice Sets the transfer validator for the collection.
     * @param transferValidator_ The address of the transfer validator.
     * @dev address(0) to disable validation.
     */
    function setTransferValidator(address transferValidator_) external onlyRoles(TRANSFER_VALIDATOR_MANAGER_ROLE) {
        address oldValidator = transferValidator;
        transferValidator = transferValidator_;

        emit TransferValidatorUpdated(oldValidator, transferValidator_);
    }

    /**
     * @dev Sets the ERC2981 royalty information for the token collection.
     * @param receiver The address of the royalty recipient.
     * @param feeNumerator The royalty fee numerator.
     */
    function setRoyaltyInfo(address receiver, uint96 feeNumerator) external onlyRoles(ROYALTY_MANAGER_ROLE) {
        _setDefaultRoyalty(receiver, feeNumerator);
    }

    /**
     * @notice Burns a token.
     * @param tokenId The token ID.
     * @dev Only the Beacon contract can burn locked tokens, enforced by _beforeTokenTransfer
     * @dev If the token is unlocked, the caller must be the owner or approved.
     */
    function burn(uint256 tokenId) external {
        if (_locked(tokenId)) {
            _burn(tokenId);
        } else {
            _burn(msg.sender, tokenId);
        }
    }

    /**
     * @notice Executes a callback for the specified GUID.
     * @param guid The GUID of the callback.
     */
    function executeCallback(bytes32 guid) external {
        if (msg.sender != BEACON_CONTRACT_ADDRESS) revert CallerNotBeacon();

        address callbackTarget = callbacks[guid];
        if (callbackTarget == address(0)) return;

        delete callbacks[guid];

        IShadowCallbackReceiver(callbackTarget).executeCallback(guid);
    }

    /**
     * @notice Returns whether the token is locked.
     * @param tokenId The token ID.
     * @return bool Whether the token is locked.
     */
    function locked(uint256 tokenId) external view returns (bool) {
        return _locked(tokenId);
    }

    /**
     * @notice Returns whether the contract supports the specified interface.
     * @param interfaceId The interface ID.
     * @return bool Whether the contract supports the interface.
     * @dev ERC721 and ERC2981 are supported.
     */
    function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) {
        return interfaceId == type(IERC5192).interfaceId || ERC721.supportsInterface(interfaceId)
            || ERC2981.supportsInterface(interfaceId) || interfaceId == bytes4(0x49064906);
    }

    /**
     * @notice Returns the token URI for the specified token ID.
     * @param id The token ID.
     * @return The token URI.
     * @dev If the metadataRenderer is set, it will be used to render the token URI.
     */
    function tokenURI(uint256 id) public view override returns (string memory) {
        if (!_exists(id)) revert TokenDoesNotExist();

        if (metadataRenderer != address(0)) {
            return ERC721(metadataRenderer).tokenURI(id);
        }

        return LibString.concat(_baseTokenUri, LibString.toString(id));
    }

    /**
     * @notice Returns the name of the collection.
     * @return _name the name of the collection.
     */
    function name() public view override returns (string memory) {
        return _name;
    }

    /**
     * @notice Returns the symbol of the collection.
     * @return _symbol the symbol of the collection.
     */
    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /**
     * @notice Returns the token IDs of the tokens owned by the specified owner in a range.
     * @dev 10k collections should be able to get all their tokens in a single call, larger collections may need pagination.
     * @dev Intended for offchain use, do not use onchain.
     * @param owner The address of the owner.
     * @param start The range start.
     * @param stop The range stop.
     * @return array of token IDs owned by the specified owner.
     */
    function tokensOfOwnerIn(address owner, uint256 start, uint256 stop) external view returns (uint256[] memory) {
        return _tokensOfOwnerIn(owner, start, stop);
    }

    /**
     * @notice Returns the ERC721C transfer validator address. address(0) indicates no validator is set.
     * @return address The address of the transfer validator.
     */
    function getTransferValidator() external view returns (address) {
        return transferValidator;
    }

    /**
     * @notice Returns the ERC721C transfer validation function signature and whether it is a view function.
     * @return functionSignature The 4 byte function signature.
     * @return isViewFunction Bool indicating if the function is a view function.
     */
    function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
        functionSignature = 0xcaee23ea;
        isViewFunction = true;
    }

    function _read(uint256[] calldata tokenIds, uint32[] calldata dstEids, uint128 callbackGasLimit)
        internal
        returns (bytes32)
    {
        address baseCollectionAddress = IBeacon(BEACON_CONTRACT_ADDRESS).shadowToBase(address(this));
        return IBeacon(BEACON_CONTRACT_ADDRESS).read{value: msg.value}(
            baseCollectionAddress, tokenIds, dstEids, msg.sender, callbackGasLimit
        );
    }

    /**
     * @notice Unlocks the specified token ID.
     * @param tokenId The token ID to unlock.
     * @param beneficiary The address of the beneficiary of the unlocked token, in case ownership is stale.
     * @dev Only the Beacon contract can unlock tokens
     */
    function _unlockToken(uint256 tokenId, address beneficiary) internal {
        if (_locked(tokenId)) {
            address owner = _ownerOf(tokenId);

            // mint if there is no previous owner, otherwise transfer
            if (owner == address(0)) {
                _mint(beneficiary, tokenId);
            } else if (beneficiary != owner) {
                _transfer(address(0), owner, beneficiary, tokenId);
            }

            _setExtraData(tokenId, UNLOCKED);

            emit Unlocked(tokenId);
        } else {
            revert TokenNotLocked();
        }
    }

    function _tokensOfOwnerIn(address owner, uint256 start, uint256 stop) internal view returns (uint256[] memory) {
        uint256 numberOfTokens = balanceOf(owner);
        uint256 tokenIdIdx = 0;
        uint256[] memory tokenIds = new uint256[](numberOfTokens);

        for (uint256 i = start; i <= stop; i++) {
            if (_ownerOf(i) == owner) {
                tokenIds[tokenIdIdx] = i;

                unchecked {
                    tokenIdIdx++;
                }

                if (tokenIdIdx == numberOfTokens) {
                    return tokenIds;
                }
            }
        }

        // in case we did not find all the tokens within this start/stop, we need to resize the array
        uint256[] memory result = new uint256[](tokenIdIdx);
        for (uint256 i = 0; i < tokenIdIdx; i++) {
            result[i] = tokenIds[i];
        }

        return result;
    }

    // tokens can only be transferred if they are locked on the source chain
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal view override {
        if (msg.sender != BEACON_CONTRACT_ADDRESS) {
            if (_locked(tokenId) || from == address(0)) {
                revert CallerNotBeacon();
            }

            if (transferValidator != address(0)) {
                ITransferValidator(transferValidator).validateTransfer(msg.sender, from, to, tokenId);
            }
        }
    }

    function _locked(uint256 tokenId) internal view returns (bool) {
        return _getExtraData(tokenId) == LOCKED;
    }

    function _guardInitializeOwner() internal pure override returns (bool) {
        return true;
    }

    function _calldataload(uint256 offset) internal pure returns (uint256 value) {
        /// @solidity memory-safe-assembly
        assembly {
            value := calldataload(offset)
        }
    }

    function _shadowFallback() internal {
        uint256 fnSelector = _calldataload(0x00) >> 224;

        if (fnSelector == 0x40c10f19) {
            // msg.sender is the Beacon contract, enforced by _beforeTokenTransfer
            _mint(address(uint160(_calldataload(0x04))), _calldataload(0x24));
        } else if (fnSelector == 0x92772833) {
            if (msg.sender != BEACON_CONTRACT_ADDRESS) revert CallerNotBeacon();

            uint256 tokenIdsLength = _calldataload(0x44);
            address beneficiary = address(uint160(_calldataload(0x24)));

            for (uint256 i = 0; i < tokenIdsLength; i++) {
                _unlockToken(_calldataload(0x64 + i * 32), beneficiary);
            }
        } else {
            revert FnSelectorNotRecognized();
        }
    }
}

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

/// @notice Simple ERC721 implementation with storage hitchhiking.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol)
///
/// @dev Note:
/// - The ERC721 standard allows for self-approvals.
///   For performance, this implementation WILL NOT revert for such actions.
///   Please add any checks with overrides if desired.
/// - For performance, methods are made payable where permitted by the ERC721 standard.
/// - The `safeTransfer` functions use the identity precompile (0x4)
///   to copy memory internally.
///
/// If you are overriding:
/// - NEVER violate the ERC721 invariant:
///   the balance of an owner MUST always be equal to their number of ownership slots.
///   The transfer functions do not have an underflow guard for user token balances.
/// - Make sure all variables written to storage are properly cleaned
//    (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC721 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev An account can hold up to 4294967295 tokens.
    uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;

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

    /// @dev Only the token owner or an approved account can manage the token.
    error NotOwnerNorApproved();

    /// @dev The token does not exist.
    error TokenDoesNotExist();

    /// @dev The token already exists.
    error TokenAlreadyExists();

    /// @dev Cannot query the balance for the zero address.
    error BalanceQueryForZeroAddress();

    /// @dev Cannot mint or transfer to the zero address.
    error TransferToZeroAddress();

    /// @dev The token must be owned by `from`.
    error TransferFromIncorrectOwner();

    /// @dev The recipient's balance has overflowed.
    error AccountBalanceOverflow();

    /// @dev Cannot safely transfer to a contract that does not implement
    /// the ERC721Receiver interface.
    error TransferToNonERC721ReceiverImplementer();

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

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    /// @dev Emitted when `owner` enables `account` to manage the `id` token.
    event Approval(address indexed owner, address indexed account, uint256 indexed id);

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

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

    /// @dev The ownership data slot of `id` is given by:
    /// ```
    ///     mstore(0x00, id)
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
    /// ```
    /// Bits Layout:
    /// - [0..159]   `addr`
    /// - [160..255] `extraData`
    ///
    /// The approved address slot is given by: `add(1, ownershipSlot)`.
    ///
    /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip
    ///
    /// The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x1c)
    /// ```
    /// Bits Layout:
    /// - [0..31]   `balance`
    /// - [32..255] `aux`
    ///
    /// The `operator` approval slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
    ///     mstore(0x00, owner)
    ///     let operatorApprovalSlot := keccak256(0x0c, 0x30)
    /// ```
    uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;

    /// @dev Pre-shifted and pre-masked constant.
    uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC721 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the token collection name.
    function name() public view virtual returns (string memory);

    /// @dev Returns the token collection symbol.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
    function tokenURI(uint256 id) public view virtual returns (string memory);

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

    /// @dev Returns the owner of token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address result) {
        result = _ownerOf(id);
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(result) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the number of tokens owned by `owner`.
    ///
    /// Requirements:
    /// - `owner` must not be the zero address.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the `owner` is the zero address.
            if iszero(owner) {
                mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`.
                revert(0x1c, 0x04)
            }
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            if iszero(shl(96, sload(ownershipSlot))) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            result := sload(add(1, ownershipSlot))
        }
    }

    /// @dev Sets `account` as the approved account to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits an {Approval} event.
    function approve(address account, uint256 id) public payable virtual {
        _approve(msg.sender, account, id);
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x30))
        }
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller.
    ///
    /// Emits an {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool isApproved) public virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`msg.sender`, `operator`).
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
        }
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public payable virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if the token does not exist, or if `from` is not the owner.
            if iszero(mul(owner, eq(owner, from))) {
                // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
                mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // Revert if the caller is not the owner, nor approved.
                if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
        public
        payable
        virtual
    {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL QUERY FUNCTIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns if token `id` exists.
    function _exists(uint256 id) internal view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))))
        }
    }

    /// @dev Returns the owner of token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _ownerOf(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            INTERNAL DATA HITCHHIKING FUNCTIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, no events are emitted for the hitchhiking setters.
    // Please emit your own events if required.

    /// @dev Returns the auxiliary data for `owner`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _getAux(address owner) internal view virtual returns (uint224 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := shr(32, sload(keccak256(0x0c, 0x1c)))
        }
    }

    /// @dev Set the auxiliary data for `owner` to `value`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _setAux(address owner, uint224 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            let balanceSlot := keccak256(0x0c, 0x1c)
            let packed := sload(balanceSlot)
            sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
        }
    }

    /// @dev Returns the extra data for token `id`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Sets the extra data for token `id` to `value`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _setExtraData(uint256 id, uint96 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let packed := sload(ownershipSlot)
            sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 id) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Revert if the token already exists.
            if shl(96, ownershipPacked) {
                mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`.
                revert(0x1c, 0x04)
            }
            // Update with the owner.
            sstore(ownershipSlot, or(ownershipPacked, to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`.
    /// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing).
    ///
    /// Requirements:
    ///
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Update with the owner and extra data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Equivalent to `_safeMint(to, id, "")`.
    function _safeMint(address to, uint256 id) internal virtual {
        _safeMint(to, id, "");
    }

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
        _mint(to, id);
        if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `_burn(address(0), id)`.
    function _burn(uint256 id) internal virtual {
        _burn(address(0), id);
    }

    /// @dev Destroys token `id`, using `by`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _burn(address by, uint256 id) internal virtual {
        address owner = ownerOf(id);
        _beforeTokenTransfer(owner, address(0), id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Reload the owner in case it is changed in `_beforeTokenTransfer`.
            owner := shr(96, shl(96, ownershipPacked))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Load and check the token approval.
            {
                mstore(0x00, owner)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Clear the owner.
            sstore(ownershipSlot, xor(ownershipPacked, owner))
            // Decrement the balance of `owner`.
            {
                let balanceSlot := keccak256(0x0c, 0x1c)
                sstore(balanceSlot, sub(sload(balanceSlot), 1))
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
        }
        _afterTokenTransfer(owner, address(0), id);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL APPROVAL FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _isApprovedOrOwner(address account, uint256 id)
        internal
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            // Clear the upper 96 bits.
            account := shr(96, shl(96, account))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := shr(96, shl(96, sload(ownershipSlot)))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Check if `account` is the `owner`.
            if iszero(eq(account, owner)) {
                mstore(0x00, owner)
                // Check if `account` is approved to manage the token.
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    result := eq(account, sload(add(1, ownershipSlot)))
                }
            }
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _getApproved(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Equivalent to `_approve(address(0), account, id)`.
    function _approve(address account, uint256 id) internal virtual {
        _approve(address(0), account, id);
    }

    /// @dev Sets `account` as the approved account to manage token `id`, using `by`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - If `by` is not the zero address, `by` must be the owner
    ///   or an approved operator for the token owner.
    ///
    /// Emits a {Approval} event.
    function _approve(address by, address account, uint256 id) internal virtual {
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            account := and(bitmaskAddress, account)
            by := and(bitmaskAddress, by)
            // Load the owner of the token.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := and(bitmaskAddress, sload(ownershipSlot))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // If `by` is not the zero address, do the authorization check.
            // Revert if `by` is not the owner, nor approved.
            if iszero(or(iszero(by), eq(by, owner))) {
                mstore(0x00, owner)
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                    revert(0x1c, 0x04)
                }
            }
            // Sets `account` as the approved account to manage `id`.
            sstore(add(1, ownershipSlot), account)
            // Emit the {Approval} event.
            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
        }
    }

    /// @dev Approve or remove the `operator` as an operator for `by`,
    /// without authorization checks.
    ///
    /// Emits an {ApprovalForAll} event.
    function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            operator := shr(96, shl(96, operator))
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`by`, `operator`).
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
            mstore(0x00, by)
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL TRANSFER FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `_transfer(address(0), from, to, id)`.
    function _transfer(address from, address to, uint256 id) internal virtual {
        _transfer(address(0), from, to, id);
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _transfer(address by, address from, address to, uint256 id) internal virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            by := and(bitmaskAddress, by)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if the token does not exist, or if `from` is not the owner.
            if iszero(mul(owner, eq(owner, from))) {
                // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
                mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `_safeTransfer(from, to, id, "")`.
    function _safeTransfer(address from, address to, uint256 id) internal virtual {
        _safeTransfer(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeTransfer(address from, address to, uint256 id, bytes memory data)
        internal
        virtual
    {
        _transfer(address(0), from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`.
    function _safeTransfer(address by, address from, address to, uint256 id) internal virtual {
        _safeTransfer(by, from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data)
        internal
        virtual
    {
        _transfer(by, from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    HOOKS FOR OVERRIDING                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Hook that is called before any token transfers, including minting and burning.
    function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {}

    /// @dev Hook that is called after any token transfers, including minting and burning.
    function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {}

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

    /// @dev Returns if `a` has bytecode of non-zero length.
    function _hasCode(address a) private view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := extcodesize(a) // Can handle dirty upper bits.
        }
    }

    /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
    /// Reverts if the target does not support the function correctly.
    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
        private
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the calldata.
            let m := mload(0x40)
            let onERC721ReceivedSelector := 0x150b7a02
            mstore(m, onERC721ReceivedSelector)
            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
            mstore(add(m, 0x40), shr(96, shl(96, from)))
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), 0x80)
            let n := mload(data)
            mstore(add(m, 0xa0), n)
            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
            // Revert if the call reverts.
            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
                if returndatasize() {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 4 of 13 : LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @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 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        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;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     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 `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length)
        internal
        pure
        returns (string memory result)
    {
        result = toHexStringNoPrefix(value, length);
        /// @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 `length` bytes.
    /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 length)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, `length * 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, length), 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(length, length))
            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 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.
            let end := add(i, mload(subject))
            if iszero(gt(needleLen, mload(subject))) {
                let subjectSearchEnd := add(sub(end, 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 n := add(sub(d, add(result, 0x20)), end)
            // Copy the rest of the string 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 string.
            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(string memory subject, string 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(string memory subject, string memory needle)
        internal
        pure
        returns (uint256 result)
    {
        result = 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(string memory subject, string 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(string memory subject, string memory needle)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, 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 indexOf(subject, needle) != NOT_FOUND;
    }

    /// @dev Returns whether `subject` starts with `needle`.
    function startsWith(string memory subject, string memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let needleLen := mload(needle)
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                iszero(gt(needleLen, mload(subject))),
                eq(
                    keccak256(add(subject, 0x20), needleLen),
                    keccak256(add(needle, 0x20), needleLen)
                )
            )
        }
    }

    /// @dev Returns whether `subject` ends with `needle`.
    function endsWith(string memory subject, string memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let needleLen := mload(needle)
            // Whether `needle` is not longer than `subject`.
            let inRange := iszero(gt(needleLen, mload(subject)))
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLen - needleLen, 0)`.
                        add(add(subject, 0x20), mul(inRange, sub(mload(subject), needleLen))),
                        needleLen
                    ),
                    keccak256(add(needle, 0x20), needleLen)
                ),
                inRange
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLen := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLen))) {
                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, subjectLen)) { break }
                    }
                    o := add(o, subjectLen)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(o, 0) // Zeroize the slot after the string.
                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(string memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLen := mload(subject)
            if iszero(gt(subjectLen, end)) { end := subjectLen }
            if iszero(gt(subjectLen, start)) { start := subjectLen }
            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 string.
                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 string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start)
        internal
        pure
        returns (string memory result)
    {
        result = slice(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 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 strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter)
        internal
        pure
        returns (string[] 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 string.
                    // 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 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 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 string.
            mstore(result, totalLen) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate memory.
        }
    }

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

File 5 of 13 : OwnableRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `user`'s roles is updated to `roles`.
    /// Each bit of `roles` represents whether the role is set.
    event RolesUpdated(address indexed user, uint256 indexed roles);

    /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
    uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
        0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;

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

    /// @dev The role slot of `user` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
    ///     let roleSlot := keccak256(0x00, 0x20)
    /// ```
    /// This automatically ignores the upper bits of the `user` in case
    /// they are not clean, as well as keep the `keccak256` under 32-bytes.
    ///
    /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
    uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Overwrite the roles directly without authorization guard.
    function _setRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Store the new value.
            sstore(keccak256(0x0c, 0x20), roles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
        }
    }

    /// @dev Updates the roles directly without authorization guard.
    /// If `on` is true, each set bit of `roles` will be turned on,
    /// otherwise, each set bit of `roles` will be turned off.
    function _updateRoles(address user, uint256 roles, bool on) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            let roleSlot := keccak256(0x0c, 0x20)
            // Load the current value.
            let current := sload(roleSlot)
            // Compute the updated roles if `on` is true.
            let updated := or(current, roles)
            // Compute the updated roles if `on` is false.
            // Use `and` to compute the intersection of `current` and `roles`,
            // `xor` it with `current` to flip the bits in the intersection.
            if iszero(on) { updated := xor(current, and(current, roles)) }
            // Then, store the new value.
            sstore(roleSlot, updated)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
        }
    }

    /// @dev Grants the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn on.
    function _grantRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, true);
    }

    /// @dev Removes the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn off.
    function _removeRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, false);
    }

    /// @dev Throws if the sender does not have any of the `roles`.
    function _checkRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Throws if the sender is not the owner,
    /// and does not have any of the `roles`.
    /// Checks for ownership first, then lazily checks for roles.
    function _checkOwnerOrRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner.
            // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
            if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                // Compute the role slot.
                mstore(0x0c, _ROLE_SLOT_SEED)
                mstore(0x00, caller())
                // Load the stored value, and if the `and` intersection
                // of the value and `roles` is zero, revert.
                if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Throws if the sender does not have any of the `roles`,
    /// and is not the owner.
    /// Checks for roles first, then lazily checks for ownership.
    function _checkRolesOrOwner(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                // If the caller is not the stored owner.
                // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
                // We don't need to mask the values of `ordinals`, as Solidity
                // cleans dirty upper bits when storing variables into memory.
                roles := or(shl(mload(add(ordinals, i)), 1), roles)
            }
        }
    }

    /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the pointer to the free memory.
            ordinals := mload(0x40)
            let ptr := add(ordinals, 0x20)
            let o := 0
            // The absence of lookup tables, De Bruijn, etc., here is intentional for
            // smaller bytecode, as this function is not meant to be called on-chain.
            for { let t := roles } 1 {} {
                mstore(ptr, o)
                // `shr` 5 is equivalent to multiplying by 0x20.
                // Push back into the ordinals array if the bit is set.
                ptr := add(ptr, shl(5, and(t, 1)))
                o := add(o, 1)
                t := shr(o, roles)
                if iszero(t) { break }
            }
            // Store the length of `ordinals`.
            mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
            // Allocate the memory.
            mstore(0x40, ptr)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to grant `user` `roles`.
    /// If the `user` already has a role, then it will be an no-op for the role.
    function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _grantRoles(user, roles);
    }

    /// @dev Allows the owner to remove `user` `roles`.
    /// If the `user` does not have a role, then it will be an no-op for the role.
    function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _removeRoles(user, roles);
    }

    /// @dev Allow the caller to remove their own roles.
    /// If the caller does not have a role, then it will be an no-op for the role.
    function renounceRoles(uint256 roles) public payable virtual {
        _removeRoles(msg.sender, roles);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the roles of `user`.
    function rolesOf(address user) public view virtual returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Load the stored value.
            roles := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns whether `user` has any of `roles`.
    function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles != 0;
    }

    /// @dev Returns whether `user` has all of `roles`.
    function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles == roles;
    }

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

    /// @dev Marks a function as only callable by an account with `roles`.
    modifier onlyRoles(uint256 roles) virtual {
        _checkRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by the owner or by an account
    /// with `roles`. Checks for ownership first, then lazily checks for roles.
    modifier onlyOwnerOrRoles(uint256 roles) virtual {
        _checkOwnerOrRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`
    /// or the owner. Checks for roles first, then lazily checks for ownership.
    modifier onlyRolesOrOwner(uint256 roles) virtual {
        _checkRolesOrOwner(roles);
        _;
    }

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

    // IYKYK

    uint256 internal constant _ROLE_0 = 1 << 0;
    uint256 internal constant _ROLE_1 = 1 << 1;
    uint256 internal constant _ROLE_2 = 1 << 2;
    uint256 internal constant _ROLE_3 = 1 << 3;
    uint256 internal constant _ROLE_4 = 1 << 4;
    uint256 internal constant _ROLE_5 = 1 << 5;
    uint256 internal constant _ROLE_6 = 1 << 6;
    uint256 internal constant _ROLE_7 = 1 << 7;
    uint256 internal constant _ROLE_8 = 1 << 8;
    uint256 internal constant _ROLE_9 = 1 << 9;
    uint256 internal constant _ROLE_10 = 1 << 10;
    uint256 internal constant _ROLE_11 = 1 << 11;
    uint256 internal constant _ROLE_12 = 1 << 12;
    uint256 internal constant _ROLE_13 = 1 << 13;
    uint256 internal constant _ROLE_14 = 1 << 14;
    uint256 internal constant _ROLE_15 = 1 << 15;
    uint256 internal constant _ROLE_16 = 1 << 16;
    uint256 internal constant _ROLE_17 = 1 << 17;
    uint256 internal constant _ROLE_18 = 1 << 18;
    uint256 internal constant _ROLE_19 = 1 << 19;
    uint256 internal constant _ROLE_20 = 1 << 20;
    uint256 internal constant _ROLE_21 = 1 << 21;
    uint256 internal constant _ROLE_22 = 1 << 22;
    uint256 internal constant _ROLE_23 = 1 << 23;
    uint256 internal constant _ROLE_24 = 1 << 24;
    uint256 internal constant _ROLE_25 = 1 << 25;
    uint256 internal constant _ROLE_26 = 1 << 26;
    uint256 internal constant _ROLE_27 = 1 << 27;
    uint256 internal constant _ROLE_28 = 1 << 28;
    uint256 internal constant _ROLE_29 = 1 << 29;
    uint256 internal constant _ROLE_30 = 1 << 30;
    uint256 internal constant _ROLE_31 = 1 << 31;
    uint256 internal constant _ROLE_32 = 1 << 32;
    uint256 internal constant _ROLE_33 = 1 << 33;
    uint256 internal constant _ROLE_34 = 1 << 34;
    uint256 internal constant _ROLE_35 = 1 << 35;
    uint256 internal constant _ROLE_36 = 1 << 36;
    uint256 internal constant _ROLE_37 = 1 << 37;
    uint256 internal constant _ROLE_38 = 1 << 38;
    uint256 internal constant _ROLE_39 = 1 << 39;
    uint256 internal constant _ROLE_40 = 1 << 40;
    uint256 internal constant _ROLE_41 = 1 << 41;
    uint256 internal constant _ROLE_42 = 1 << 42;
    uint256 internal constant _ROLE_43 = 1 << 43;
    uint256 internal constant _ROLE_44 = 1 << 44;
    uint256 internal constant _ROLE_45 = 1 << 45;
    uint256 internal constant _ROLE_46 = 1 << 46;
    uint256 internal constant _ROLE_47 = 1 << 47;
    uint256 internal constant _ROLE_48 = 1 << 48;
    uint256 internal constant _ROLE_49 = 1 << 49;
    uint256 internal constant _ROLE_50 = 1 << 50;
    uint256 internal constant _ROLE_51 = 1 << 51;
    uint256 internal constant _ROLE_52 = 1 << 52;
    uint256 internal constant _ROLE_53 = 1 << 53;
    uint256 internal constant _ROLE_54 = 1 << 54;
    uint256 internal constant _ROLE_55 = 1 << 55;
    uint256 internal constant _ROLE_56 = 1 << 56;
    uint256 internal constant _ROLE_57 = 1 << 57;
    uint256 internal constant _ROLE_58 = 1 << 58;
    uint256 internal constant _ROLE_59 = 1 << 59;
    uint256 internal constant _ROLE_60 = 1 << 60;
    uint256 internal constant _ROLE_61 = 1 << 61;
    uint256 internal constant _ROLE_62 = 1 << 62;
    uint256 internal constant _ROLE_63 = 1 << 63;
    uint256 internal constant _ROLE_64 = 1 << 64;
    uint256 internal constant _ROLE_65 = 1 << 65;
    uint256 internal constant _ROLE_66 = 1 << 66;
    uint256 internal constant _ROLE_67 = 1 << 67;
    uint256 internal constant _ROLE_68 = 1 << 68;
    uint256 internal constant _ROLE_69 = 1 << 69;
    uint256 internal constant _ROLE_70 = 1 << 70;
    uint256 internal constant _ROLE_71 = 1 << 71;
    uint256 internal constant _ROLE_72 = 1 << 72;
    uint256 internal constant _ROLE_73 = 1 << 73;
    uint256 internal constant _ROLE_74 = 1 << 74;
    uint256 internal constant _ROLE_75 = 1 << 75;
    uint256 internal constant _ROLE_76 = 1 << 76;
    uint256 internal constant _ROLE_77 = 1 << 77;
    uint256 internal constant _ROLE_78 = 1 << 78;
    uint256 internal constant _ROLE_79 = 1 << 79;
    uint256 internal constant _ROLE_80 = 1 << 80;
    uint256 internal constant _ROLE_81 = 1 << 81;
    uint256 internal constant _ROLE_82 = 1 << 82;
    uint256 internal constant _ROLE_83 = 1 << 83;
    uint256 internal constant _ROLE_84 = 1 << 84;
    uint256 internal constant _ROLE_85 = 1 << 85;
    uint256 internal constant _ROLE_86 = 1 << 86;
    uint256 internal constant _ROLE_87 = 1 << 87;
    uint256 internal constant _ROLE_88 = 1 << 88;
    uint256 internal constant _ROLE_89 = 1 << 89;
    uint256 internal constant _ROLE_90 = 1 << 90;
    uint256 internal constant _ROLE_91 = 1 << 91;
    uint256 internal constant _ROLE_92 = 1 << 92;
    uint256 internal constant _ROLE_93 = 1 << 93;
    uint256 internal constant _ROLE_94 = 1 << 94;
    uint256 internal constant _ROLE_95 = 1 << 95;
    uint256 internal constant _ROLE_96 = 1 << 96;
    uint256 internal constant _ROLE_97 = 1 << 97;
    uint256 internal constant _ROLE_98 = 1 << 98;
    uint256 internal constant _ROLE_99 = 1 << 99;
    uint256 internal constant _ROLE_100 = 1 << 100;
    uint256 internal constant _ROLE_101 = 1 << 101;
    uint256 internal constant _ROLE_102 = 1 << 102;
    uint256 internal constant _ROLE_103 = 1 << 103;
    uint256 internal constant _ROLE_104 = 1 << 104;
    uint256 internal constant _ROLE_105 = 1 << 105;
    uint256 internal constant _ROLE_106 = 1 << 106;
    uint256 internal constant _ROLE_107 = 1 << 107;
    uint256 internal constant _ROLE_108 = 1 << 108;
    uint256 internal constant _ROLE_109 = 1 << 109;
    uint256 internal constant _ROLE_110 = 1 << 110;
    uint256 internal constant _ROLE_111 = 1 << 111;
    uint256 internal constant _ROLE_112 = 1 << 112;
    uint256 internal constant _ROLE_113 = 1 << 113;
    uint256 internal constant _ROLE_114 = 1 << 114;
    uint256 internal constant _ROLE_115 = 1 << 115;
    uint256 internal constant _ROLE_116 = 1 << 116;
    uint256 internal constant _ROLE_117 = 1 << 117;
    uint256 internal constant _ROLE_118 = 1 << 118;
    uint256 internal constant _ROLE_119 = 1 << 119;
    uint256 internal constant _ROLE_120 = 1 << 120;
    uint256 internal constant _ROLE_121 = 1 << 121;
    uint256 internal constant _ROLE_122 = 1 << 122;
    uint256 internal constant _ROLE_123 = 1 << 123;
    uint256 internal constant _ROLE_124 = 1 << 124;
    uint256 internal constant _ROLE_125 = 1 << 125;
    uint256 internal constant _ROLE_126 = 1 << 126;
    uint256 internal constant _ROLE_127 = 1 << 127;
    uint256 internal constant _ROLE_128 = 1 << 128;
    uint256 internal constant _ROLE_129 = 1 << 129;
    uint256 internal constant _ROLE_130 = 1 << 130;
    uint256 internal constant _ROLE_131 = 1 << 131;
    uint256 internal constant _ROLE_132 = 1 << 132;
    uint256 internal constant _ROLE_133 = 1 << 133;
    uint256 internal constant _ROLE_134 = 1 << 134;
    uint256 internal constant _ROLE_135 = 1 << 135;
    uint256 internal constant _ROLE_136 = 1 << 136;
    uint256 internal constant _ROLE_137 = 1 << 137;
    uint256 internal constant _ROLE_138 = 1 << 138;
    uint256 internal constant _ROLE_139 = 1 << 139;
    uint256 internal constant _ROLE_140 = 1 << 140;
    uint256 internal constant _ROLE_141 = 1 << 141;
    uint256 internal constant _ROLE_142 = 1 << 142;
    uint256 internal constant _ROLE_143 = 1 << 143;
    uint256 internal constant _ROLE_144 = 1 << 144;
    uint256 internal constant _ROLE_145 = 1 << 145;
    uint256 internal constant _ROLE_146 = 1 << 146;
    uint256 internal constant _ROLE_147 = 1 << 147;
    uint256 internal constant _ROLE_148 = 1 << 148;
    uint256 internal constant _ROLE_149 = 1 << 149;
    uint256 internal constant _ROLE_150 = 1 << 150;
    uint256 internal constant _ROLE_151 = 1 << 151;
    uint256 internal constant _ROLE_152 = 1 << 152;
    uint256 internal constant _ROLE_153 = 1 << 153;
    uint256 internal constant _ROLE_154 = 1 << 154;
    uint256 internal constant _ROLE_155 = 1 << 155;
    uint256 internal constant _ROLE_156 = 1 << 156;
    uint256 internal constant _ROLE_157 = 1 << 157;
    uint256 internal constant _ROLE_158 = 1 << 158;
    uint256 internal constant _ROLE_159 = 1 << 159;
    uint256 internal constant _ROLE_160 = 1 << 160;
    uint256 internal constant _ROLE_161 = 1 << 161;
    uint256 internal constant _ROLE_162 = 1 << 162;
    uint256 internal constant _ROLE_163 = 1 << 163;
    uint256 internal constant _ROLE_164 = 1 << 164;
    uint256 internal constant _ROLE_165 = 1 << 165;
    uint256 internal constant _ROLE_166 = 1 << 166;
    uint256 internal constant _ROLE_167 = 1 << 167;
    uint256 internal constant _ROLE_168 = 1 << 168;
    uint256 internal constant _ROLE_169 = 1 << 169;
    uint256 internal constant _ROLE_170 = 1 << 170;
    uint256 internal constant _ROLE_171 = 1 << 171;
    uint256 internal constant _ROLE_172 = 1 << 172;
    uint256 internal constant _ROLE_173 = 1 << 173;
    uint256 internal constant _ROLE_174 = 1 << 174;
    uint256 internal constant _ROLE_175 = 1 << 175;
    uint256 internal constant _ROLE_176 = 1 << 176;
    uint256 internal constant _ROLE_177 = 1 << 177;
    uint256 internal constant _ROLE_178 = 1 << 178;
    uint256 internal constant _ROLE_179 = 1 << 179;
    uint256 internal constant _ROLE_180 = 1 << 180;
    uint256 internal constant _ROLE_181 = 1 << 181;
    uint256 internal constant _ROLE_182 = 1 << 182;
    uint256 internal constant _ROLE_183 = 1 << 183;
    uint256 internal constant _ROLE_184 = 1 << 184;
    uint256 internal constant _ROLE_185 = 1 << 185;
    uint256 internal constant _ROLE_186 = 1 << 186;
    uint256 internal constant _ROLE_187 = 1 << 187;
    uint256 internal constant _ROLE_188 = 1 << 188;
    uint256 internal constant _ROLE_189 = 1 << 189;
    uint256 internal constant _ROLE_190 = 1 << 190;
    uint256 internal constant _ROLE_191 = 1 << 191;
    uint256 internal constant _ROLE_192 = 1 << 192;
    uint256 internal constant _ROLE_193 = 1 << 193;
    uint256 internal constant _ROLE_194 = 1 << 194;
    uint256 internal constant _ROLE_195 = 1 << 195;
    uint256 internal constant _ROLE_196 = 1 << 196;
    uint256 internal constant _ROLE_197 = 1 << 197;
    uint256 internal constant _ROLE_198 = 1 << 198;
    uint256 internal constant _ROLE_199 = 1 << 199;
    uint256 internal constant _ROLE_200 = 1 << 200;
    uint256 internal constant _ROLE_201 = 1 << 201;
    uint256 internal constant _ROLE_202 = 1 << 202;
    uint256 internal constant _ROLE_203 = 1 << 203;
    uint256 internal constant _ROLE_204 = 1 << 204;
    uint256 internal constant _ROLE_205 = 1 << 205;
    uint256 internal constant _ROLE_206 = 1 << 206;
    uint256 internal constant _ROLE_207 = 1 << 207;
    uint256 internal constant _ROLE_208 = 1 << 208;
    uint256 internal constant _ROLE_209 = 1 << 209;
    uint256 internal constant _ROLE_210 = 1 << 210;
    uint256 internal constant _ROLE_211 = 1 << 211;
    uint256 internal constant _ROLE_212 = 1 << 212;
    uint256 internal constant _ROLE_213 = 1 << 213;
    uint256 internal constant _ROLE_214 = 1 << 214;
    uint256 internal constant _ROLE_215 = 1 << 215;
    uint256 internal constant _ROLE_216 = 1 << 216;
    uint256 internal constant _ROLE_217 = 1 << 217;
    uint256 internal constant _ROLE_218 = 1 << 218;
    uint256 internal constant _ROLE_219 = 1 << 219;
    uint256 internal constant _ROLE_220 = 1 << 220;
    uint256 internal constant _ROLE_221 = 1 << 221;
    uint256 internal constant _ROLE_222 = 1 << 222;
    uint256 internal constant _ROLE_223 = 1 << 223;
    uint256 internal constant _ROLE_224 = 1 << 224;
    uint256 internal constant _ROLE_225 = 1 << 225;
    uint256 internal constant _ROLE_226 = 1 << 226;
    uint256 internal constant _ROLE_227 = 1 << 227;
    uint256 internal constant _ROLE_228 = 1 << 228;
    uint256 internal constant _ROLE_229 = 1 << 229;
    uint256 internal constant _ROLE_230 = 1 << 230;
    uint256 internal constant _ROLE_231 = 1 << 231;
    uint256 internal constant _ROLE_232 = 1 << 232;
    uint256 internal constant _ROLE_233 = 1 << 233;
    uint256 internal constant _ROLE_234 = 1 << 234;
    uint256 internal constant _ROLE_235 = 1 << 235;
    uint256 internal constant _ROLE_236 = 1 << 236;
    uint256 internal constant _ROLE_237 = 1 << 237;
    uint256 internal constant _ROLE_238 = 1 << 238;
    uint256 internal constant _ROLE_239 = 1 << 239;
    uint256 internal constant _ROLE_240 = 1 << 240;
    uint256 internal constant _ROLE_241 = 1 << 241;
    uint256 internal constant _ROLE_242 = 1 << 242;
    uint256 internal constant _ROLE_243 = 1 << 243;
    uint256 internal constant _ROLE_244 = 1 << 244;
    uint256 internal constant _ROLE_245 = 1 << 245;
    uint256 internal constant _ROLE_246 = 1 << 246;
    uint256 internal constant _ROLE_247 = 1 << 247;
    uint256 internal constant _ROLE_248 = 1 << 248;
    uint256 internal constant _ROLE_249 = 1 << 249;
    uint256 internal constant _ROLE_250 = 1 << 250;
    uint256 internal constant _ROLE_251 = 1 << 251;
    uint256 internal constant _ROLE_252 = 1 << 252;
    uint256 internal constant _ROLE_253 = 1 << 253;
    uint256 internal constant _ROLE_254 = 1 << 254;
    uint256 internal constant _ROLE_255 = 1 << 255;
}

File 6 of 13 : ERC2981.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC2981 NFT Royalty Standard implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol)
abstract contract ERC2981 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The royalty fee numerator exceeds the fee denominator.
    error RoyaltyOverflow();

    /// @dev The royalty receiver cannot be the zero address.
    error RoyaltyReceiverIsZeroAddress();

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

    /// @dev The default royalty info is given by:
    /// ```
    ///     let packed := sload(_ERC2981_MASTER_SLOT_SEED)
    ///     let receiver := shr(96, packed)
    ///     let royaltyFraction := xor(packed, shl(96, receiver))
    /// ```
    ///
    /// The per token royalty info is given by.
    /// ```
    ///     mstore(0x00, tokenId)
    ///     mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
    ///     let packed := sload(keccak256(0x00, 0x40))
    ///     let receiver := shr(96, packed)
    ///     let royaltyFraction := xor(packed, shl(96, receiver))
    /// ```
    uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7;

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

    /// @dev Checks that `_feeDenominator` is non-zero.
    constructor() {
        require(_feeDenominator() != 0, "Fee denominator cannot be zero.");
    }

    /// @dev Returns the denominator for the royalty amount.
    /// Defaults to 10000, which represents fees in basis points.
    /// Override this function to return a custom amount if needed.
    function _feeDenominator() internal pure virtual returns (uint96) {
        return 10000;
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a.
            result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a))
        }
    }

    /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`.
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        public
        view
        virtual
        returns (address receiver, uint256 royaltyAmount)
    {
        uint256 feeDenominator = _feeDenominator();
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, tokenId)
            mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
            let packed := sload(keccak256(0x00, 0x40))
            receiver := shr(96, packed)
            if iszero(receiver) {
                packed := sload(mload(0x20))
                receiver := shr(96, packed)
            }
            let x := salePrice
            let y := xor(packed, shl(96, receiver)) // `feeNumerator`.
            // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            // Out-of-gas revert. Should not be triggered in practice, but included for safety.
            returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y))))
            royaltyAmount := div(mul(x, y), feeDenominator)
        }
    }

    /// @dev Sets the default royalty `receiver` and `feeNumerator`.
    ///
    /// Requirements:
    /// - `receiver` must not be the zero address.
    /// - `feeNumerator` must not be greater than the fee denominator.
    function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
        uint256 feeDenominator = _feeDenominator();
        /// @solidity memory-safe-assembly
        assembly {
            feeNumerator := shr(160, shl(160, feeNumerator))
            if gt(feeNumerator, feeDenominator) {
                mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                revert(0x1c, 0x04)
            }
            let packed := shl(96, receiver)
            if iszero(packed) {
                mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
            sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator))
        }
    }

    /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero.
    function _deleteDefaultRoyalty() internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            sstore(_ERC2981_MASTER_SLOT_SEED, 0)
        }
    }

    /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`.
    ///
    /// Requirements:
    /// - `receiver` must not be the zero address.
    /// - `feeNumerator` must not be greater than the fee denominator.
    function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
        internal
        virtual
    {
        uint256 feeDenominator = _feeDenominator();
        /// @solidity memory-safe-assembly
        assembly {
            feeNumerator := shr(160, shl(160, feeNumerator))
            if gt(feeNumerator, feeDenominator) {
                mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                revert(0x1c, 0x04)
            }
            let packed := shl(96, receiver)
            if iszero(packed) {
                mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, tokenId)
            mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
            sstore(keccak256(0x00, 0x40), or(packed, feeNumerator))
        }
    }

    /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero.
    function _resetTokenRoyalty(uint256 tokenId) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, tokenId)
            mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
            sstore(keccak256(0x00, 0x40), 0)
        }
    }
}

File 7 of 13 : IERC5192.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

interface IERC5192 {
    /// @notice Emitted when the locking status is changed to locked.
    /// @dev If a token is minted and the status is locked, this event should be emitted.
    /// @param tokenId The identifier for a token.
    event Locked(uint256 tokenId);

    /// @notice Emitted when the locking status is changed to unlocked.
    /// @dev If a token is minted and the status is unlocked, this event should be emitted.
    /// @param tokenId The identifier for a token.
    event Unlocked(uint256 tokenId);

    /// @notice Returns the locking status of an Soulbound Token
    /// @dev SBTs assigned to zero address are considered invalid, and queries
    /// about them do throw.
    /// @param tokenId The identifier for an SBT.
    function locked(uint256 tokenId) external view returns (bool);
}

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

import {CollectionConfig} from "../structs/CollectionConfig.sol";

interface IBeacon {
    function read(
        address contractAddress,
        uint256[] calldata tokenIds,
        uint32[] calldata eids,
        address refundRecipient,
        uint128 callbackGasLimit
    ) external payable returns (bytes32);
    function send(
        uint32 eid,
        address collection,
        uint256[] calldata tokenIds,
        address beneficiary,
        address refundRecipient,
        uint128 supplementalGasLimit
    ) external payable;
    function getSendOptions(address collectionAddress, uint256[] calldata tokenIds)
        external
        view
        returns (bytes memory);
    function getReadOptions(address collectionAddress, uint256[] calldata tokenIds, uint128 callbackGasLimit)
        external
        view
        returns (bytes memory);
    function quoteSend(uint32 eid, address collectionAddress, uint256[] calldata tokenIds, bytes calldata _options)
        external
        view
        returns (uint256 nativeFee, uint256 lzTokenFee);
    function quoteRead(
        address collectionAddress,
        uint256[] calldata tokenIds,
        uint32[] calldata eids,
        bytes calldata _options
    ) external view returns (uint256 nativeFee, uint256 lzTokenFee);
    function registerCollection(
        address _shadowAddress,
        uint32 _baseCollectionChainId,
        address _baseCollectionAddress,
        uint32 _baseCollectionEid,
        uint32 _baseCollectionPerNftOwnershipUpdateCost
    ) external;
    function shadowToBase(address _shadowAddress) external view returns (address);
    function baseToShadow(address _baseAddress) external view returns (address);
    function collectionConfigs(address _shadowAddress) external view returns (CollectionConfig memory);
}

File 9 of 13 : ICreatorToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface ICreatorToken {
    event TransferValidatorUpdated(address oldValidator, address newValidator);

    function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction);
    function getTransferValidator() external view returns (address validator);
    function setTransferValidator(address validator) external;
}

File 10 of 13 : ITransferValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface ITransferValidator {
    function validateTransfer(address caller, address from, address to) external view;
    function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
    function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
}

File 11 of 13 : IShadowCallbackReceiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

interface IShadowCallbackReceiver {
    function executeCallback(bytes32 guid) external;
}

File 12 of 13 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

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

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

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

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 13 of 13 : CollectionConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

struct CollectionConfig {
    uint32 baseCollectionChainId;
    uint32 baseCollectionEid;
    uint32 baseCollectionPerNftOwnershipUpdateCost; // cost of transferring an NFT from the base collection. If 0, default of 100_000 is used
    address shadowAddress; // Local shadow address for this chain
}

Settings
{
  "remappings": [
    "solady/=lib/solady/src/",
    "@layerzerolabs/=node_modules/@layerzerolabs/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CallerNotBeacon","type":"error"},{"inputs":[],"name":"FnSelectorNotRecognized","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenLocked","type":"error"},{"inputs":[],"name":"TokenNotLocked","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"metadataRenderer","type":"address"}],"name":"MetadataRendererSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"ShadowModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unlocked","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"BEACON_CONTRACT_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"METADATA_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHADOW_MODE_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_VALIDATOR_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"callbacks","outputs":[{"internalType":"address","name":"callbackTarget","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"enableShadowMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"executeCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"string","name":"_collectionName","type":"string"},{"internalType":"string","name":"_collectionSymbol","type":"string"},{"internalType":"string","name":"_baseTokenURI","type":"string"},{"internalType":"address","name":"_metadataRenderer","type":"address"},{"internalType":"address","name":"_transferValidator","type":"address"},{"internalType":"uint96","name":"_royaltyFeeNumerator","type":"uint96"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"eids","type":"uint32[]"}],"name":"read","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"eids","type":"uint32[]"},{"internalType":"uint128","name":"callbackGasLimit","type":"uint128"}],"name":"readWithCallback","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"refundRecipient","type":"address"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"send","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_metadataRenderer","type":"address"}],"name":"setMetadataRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shadowModeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"transferValidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a060405234801561000f575f5ffd5b506df87b8230c9233b00474eda1e1b3b60805260408051808201825260088082526751303074616e747360c01b602080840191909152835180850185529182526771303074616e747360c01b8282015283519081019093525f8084526100a39373e880c31c8118103ab49b604e281283e489a69780939291737df5c32827f0fa448392ce58231ce4f378ce56e590806100a8565b610313565b60026100b48582610259565b5060036100c18782610259565b5060046100ce8682610259565b50600580546001600160a01b0319166001600160a01b0385161790556100f387610120565b5f80546001600160a01b0319166001600160a01b0384161790556101178782610178565b50505050505050565b638b78c6d81980541561013a57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6001600160601b0316612710808211156101995763350a88b35f526004601cfd5b8260601b806101af5763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806101e957607f821691505b60208210810361020757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561025457805f5260205f20601f840160051c810160208510156102325750805b601f840160051c820191505b81811015610251575f815560010161023e565b50505b505050565b81516001600160401b03811115610272576102726101c1565b6102868161028084546101d5565b8461020d565b6020601f8211600181146102b8575f83156102a15750848201515b5f19600385901b1c1916600184901b178455610251565b5f84815260208120601f198516915b828110156102e757878501518255602094850194600190920191016102c7565b508482101561030457868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b608051612ba26103635f395f818161030a0152818161094801528181610ca701528181610d1c01528181610e09015281816111a5015281816118e80152818161195501526120220152612ba25ff3fe6080604052600436106102e3575f3560e01c8063529470e81161018f578063a9fc664e116100db578063e985e9c511610094578063f2fde38b1161006e578063f2fde38b1461089a578063f7dec9b4146108ad578063fd4fe8a8146108c0578063fee81cf4146108df576102e3565b8063e985e9c51461083c578063ed06167814610870578063f04e283e14610887576102e3565b8063a9fc664e1461078e578063b1dae618146107ad578063b45a3c0e146107cc578063b88d4fde146107eb578063c87b56dd146107fe578063e0df5b6f1461081d576102e3565b8063715018a6116101485780638da5cb5b116101225780638da5cb5b1461071757806395d89b411461072f57806399a2557a14610743578063a22cb4651461076f576102e3565b8063715018a6146106d05780637347ebb9146106d85780638528e8d3146106f8576102e3565b8063529470e81461063b57806354d1f13d1461065457806358456fb51461065c5780636352211e14610673578063703199701461069257806370a08231146106b1576102e3565b80631c10893f1161024e57806329e38d5e1161020757806342842e0e116101e157806342842e0e146105c157806342966c68146105d45780634a4ee7b1146105f3578063514e62fc14610606576102e3565b806329e38d5e146105345780632a55205a146105525780632de9480714610590576102e3565b80631c10893f146104895780631cd64df41461049c5780631de26e8e146104d157806321f36509146104e557806323b872dd14610519578063256929621461052c576102e3565b8063098144d4116102a0578063098144d4146103ea5780630a212100146104065780630c756a78146104195780630d705df61461043c578063156c2c3214610463578063183a4f6e14610476576102e3565b806301ddc8bf146102f957806301ffc9a71461034957806302fa7c471461037857806306fdde0314610397578063081812fc146103b8578063095ea7b3146103d7575b3480156102ee575f5ffd5b506102f7610910565b005b348015610304575f5ffd5b5061032c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610354575f5ffd5b50610368610363366004612150565b6109e3565b6040519015158152602001610340565b348015610383575f5ffd5b506102f76103923660046121ac565b610a63565b3480156103a2575f5ffd5b506103ab610a80565b60405161034091906121df565b3480156103c3575f5ffd5b5061032c6103d2366004612214565b610b10565b6102f76103e536600461222b565b610b4b565b3480156103f5575f5ffd5b505f546001600160a01b031661032c565b6102f76104143660046122c5565b610b5a565b348015610424575f5ffd5b5061042e61200081565b604051908152602001610340565b348015610447575f5ffd5b506040805163657711f560e11b81526001602082015201610340565b61042e610471366004612347565b610daa565b6102f7610484366004612214565b610dc1565b6102f761049736600461222b565b610dcb565b3480156104a7575f5ffd5b506103686104b636600461222b565b638b78c6d8600c9081525f9290925260209091205481161490565b3480156104dc575f5ffd5b506102f7610ddd565b3480156104f0575f5ffd5b5061032c6104ff366004612214565b60016020525f90815260409020546001600160a01b031681565b6102f76105273660046123b1565b610dff565b6102f7610e94565b34801561053f575f5ffd5b505f5461032c906001600160a01b031681565b34801561055d575f5ffd5b5061057161056c3660046123ef565b610ee0565b604080516001600160a01b039093168352602083019190915201610340565b34801561059b575f5ffd5b5061042e6105aa36600461240f565b638b78c6d8600c9081525f91909152602090205490565b6102f76105cf3660046123b1565b610f33565b3480156105df575f5ffd5b506102f76105ee366004612214565b610f5f565b6102f761060136600461222b565b610f80565b348015610611575f5ffd5b5061036861062036600461222b565b638b78c6d8600c9081525f9290925260209091205416151590565b348015610646575f5ffd5b5061042e6504000000000081565b6102f7610f92565b348015610667575f5ffd5b5061042e600160581b81565b34801561067e575f5ffd5b5061032c61068d366004612214565b610fcb565b34801561069d575f5ffd5b5060055461032c906001600160a01b031681565b3480156106bc575f5ffd5b5061042e6106cb36600461240f565b610fee565b6102f7611026565b3480156106e3575f5ffd5b5060055461036890600160a01b900460ff1681565b348015610703575f5ffd5b506102f76107123660046124e6565b611039565b348015610722575f5ffd5b50638b78c6d8195461032c565b34801561073a575f5ffd5b506103ab6110b1565b34801561074e575f5ffd5b5061076261075d3660046125b4565b6110c0565b60405161034091906125e6565b34801561077a575f5ffd5b506102f7610789366004612628565b6110d7565b348015610799575f5ffd5b506102f76107a836600461240f565b61112a565b3480156107b8575f5ffd5b506102f76107c7366004612214565b61119a565b3480156107d7575f5ffd5b506103686107e6366004612214565b611277565b6102f76107f9366004612663565b611281565b348015610809575f5ffd5b506103ab610818366004612214565b6112db565b348015610828575f5ffd5b506102f76108373660046126fa565b611439565b348015610847575f5ffd5b50610368610856366004612733565b601c52670a5a2e7a000000006008525f526030600c205490565b34801561087b575f5ffd5b5061042e600160451b81565b6102f761089536600461240f565b611494565b6102f76108a836600461240f565b6114ce565b61042e6108bb36600461275f565b6114f4565b3480156108cb575f5ffd5b506102f76108da36600461240f565b61152c565b3480156108ea575f5ffd5b5061042e6108f936600461240f565b63389a75e1600c9081525f91909152602090205490565b5f3560e01c6340c10f198190036109325761092f6004356024356115b8565b50565b806392772833036109ca57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109865760405163db70dad160e01b815260040160405180910390fd5b6044356024355f5b828110156109c4576109bc6109b66109a78360206127f1565b6109b2906064612808565b3590565b8361164c565b60010161098e565b50505050565b604051631e085ca760e11b815260040160405180910390fd5b5f6001600160e01b03198216635a2d1e0760e11b1480610a245750610a24826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b80610a425750632a55205a60e083901c9081146301ffc9a791909114175b80610a5d57506001600160e01b03198216632483248360e11b145b92915050565b600160581b610a71816116fc565b610a7b8383611720565b505050565b606060038054610a8f9061281b565b80601f0160208091040260200160405190810160405280929190818152602001828054610abb9061281b565b8015610b065780601f10610add57610100808354040283529160200191610b06565b820191905f5260205f20905b815481529060010190602001808311610ae957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610b415763ceea21b65f526004601cfd5b6001015492915050565b610b56338383611769565b5050565b5f5b84811015610c8f57610b8633878784818110610b7a57610b7a612853565b90506020020135611803565b610ba35760405163096dcfe360e31b815260040160405180910390fd5b610bc4868683818110610bb857610bb8612853565b9050602002013561186c565b15610be257604051635a8181f760e01b815260040160405180910390fd5b600554600160a01b900460ff16610c1457610c14868683818110610c0857610c08612853565b9050602002013561188e565b610c36868683818110610c2957610c29612853565b905060200201355f611898565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a1611868683818110610c6957610c69612853565b90506020020135604051610c7f91815260200190565b60405180910390a1600101610b5c565b5060405163f174883560e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f174883590602401602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d189190612867565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c9df81673489848a8a8a8a8a6040518963ffffffff1660e01b8152600401610d7397969594939291906128b2565b5f604051808303818588803b158015610d8a575f5ffd5b505af1158015610d9c573d5f5f3e3d5ffd5b505050505050505050505050565b5f610db8858585855f6118c7565b95945050505050565b61092f33826119f8565b610dd3611a03565b610b568282611a1d565b612000610de9816116fc565b506005805460ff60a01b1916600160a01b179055565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163303610e89576001610e56825f818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b6001600160601b031603610e7d576040516305b166a360e41b815260040160405180910390fd5b610a7b5f848484611a29565b610a7b838383611b23565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f82815268aa4ec00224afccfdb76020526040812054606081901c91906127109083610f13576020515490508060601c93505b606084901b18845f19829004811182023d3d3e9396930204935090915050565b610f3e838383610dff565b813b15610a7b57610a7b83838360405180602001604052805f815250611c14565b610f688161186c565b15610f765761092f8161188e565b61092f3382611c95565b610f88611a03565b610b5682826119f8565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b5f610fd582611d53565b905080610fe95763ceea21b65f526004601cfd5b919050565b5f8161100157638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b61102e611a03565b6110375f611d7a565b565b6002611045858261295a565b506003611052878261295a565b50600461105f868261295a565b50600580546001600160a01b0319166001600160a01b03851617905561108487611dc0565b5f80546001600160a01b0319166001600160a01b0384161790556110a88782611720565b50505050505050565b606060048054610a8f9061281b565b60606110cd848484611e18565b90505b9392505050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b600160451b611138816116fc565b5f80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91015b60405180910390a1505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111e35760405163db70dad160e01b815260040160405180910390fd5b5f818152600160205260409020546001600160a01b031680611203575050565b5f828152600160205260409081902080546001600160a01b03191690555163163b5cc360e31b8152600481018390526001600160a01b0382169063b1dae618906024015f604051808303815f87803b15801561125d575f5ffd5b505af115801561126f573d5f5f3e3d5ffd5b505050505050565b5f610a5d8261186c565b61128c858585610dff565b833b156112d4576112d485858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1492505050565b5050505050565b6060611304825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6113215760405163677510db60e11b815260040160405180910390fd5b6005546001600160a01b03161561139f5760055460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd906024015f60405180830381865afa158015611378573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a5d9190810190612a14565b610a5d600280546113af9061281b565b80601f01602080910402602001604051908101604052809291908181526020018280546113db9061281b565b80156114265780601f106113fd57610100808354040283529160200191611426565b820191905f5260205f20905b81548152906001019060200180831161140957829003601f168201915b505050505061143484611f7a565b611fbc565b65040000000000611449816116fc565b6002611455838261295a565b50604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91015b60405180910390a15050565b61149c611a03565b63389a75e1600c52805f526020600c2080544211156114c257636f5e88185f526004601cfd5b5f905561092f81611d7a565b6114d6611a03565b8060601b6114eb57637448fbae5f526004601cfd5b61092f81611d7a565b5f5f61150387878787876118c7565b5f81815260016020526040902080546001600160a01b0319163317905591505095945050505050565b6504000000000061153c816116fc565b600580546001600160a01b0319166001600160a01b0384169081179091556040517faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a03905f90a2604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9101611488565b6115c35f8383612017565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b156115fe5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026116325767ea553b3401336cea841560021b526004601cfd5b905580825f5f516020612b4d5f395f51905f528138a45050565b6116558261186c565b156116e3575f61166483611d53565b90506001600160a01b0381166116835761167e82846115b8565b6116a8565b806001600160a01b0316826001600160a01b0316146116a8576116a85f828486611a29565b6116b3836001611898565b6040518381527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429060200161118d565b6040516305b166a360e41b815260040160405180910390fd5b638b78c6d8600c52335f52806020600c20541661092f576382b429005f526004601cfd5b6001600160601b0316612710808211156117415763350a88b35f526004601cfd5b8260601b806117575763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816117ac5763ceea21b65f526004601cfd5b8185148515176117d057815f526030600c20546117d057634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919360019216806118465763ceea21b65f526004601cfd5b80851461186457805f526030600c2054611864578160010154851492505b505092915050565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b61092f5f82611c95565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60405163f174883560e01b81523060048201525f9081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f174883590602401602060405180830381865afa15801561192d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119519190612867565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fe084c8f34838a8a8a8a338b6040518963ffffffff1660e01b81526004016119ac9796959493929190612a88565b60206040518083038185885af11580156119c8573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119ed9190612b1d565b979650505050505050565b610b5682825f6120f9565b638b78c6d819543314611037576382b429005f526004601cfd5b610b56828260016120f9565b611a34838383612017565b5f8181526001600160a01b03948516673ec412a9852d173d60c11b8117601c526020909120820182018054919594851694938416938216918286148302611a8a5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082871486881417871517611ab9576030600c2054611ab957634b6e7f185f526004601cfd5b8215611ac6575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611b075767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a450505050565b611b2e838383612017565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302611b7f5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417611bab576030600c2054611bab57634b6e7f185f526004601cfd5b8215611bb8575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611bf95767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a4505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611c5b578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611c7c573d15611c7c573d5f843e3d83fd5b508060e01b82511461126f5763d1a57ed65f526004601cfd5b5f611c9f82610fcb565b9050611cac815f84612017565b505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919382169182611cef5763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611d1c576030600c2054611d1c57634b6e7f185f526004601cfd5b8015611d29575f83600101555b5082189055601c600c2080545f19019055815f825f516020612b4d5f395f51905f528238a4505050565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b638b78c6d819805415611dda57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60605f611e2485610fee565b90505f80826001600160401b03811115611e4057611e4061242a565b604051908082528060200260200182016040528015611e69578160200160208202803683370190505b509050855b858111611edf57876001600160a01b0316611e8882611d53565b6001600160a01b031603611ecd5780828481518110611ea957611ea9612853565b602090810291909101015260018084019385900301611ecd575092506110d0915050565b80611ed781612b34565b915050611e6e565b505f826001600160401b03811115611ef957611ef961242a565b604051908082528060200260200182016040528015611f22578160200160208202803683370190505b5090505f5b83811015611f6e57828181518110611f4157611f41612853565b6020026020010151828281518110611f5b57611f5b612853565b6020908102919091010152600101611f27565b50979650505050505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a900480611f93575050819003601f19909101908152919050565b6040518251601f19906020810182165b8581015184820152820180611fcc575083518184018360208301165b8681015182820152840180611fe85750505f910183810160208101929092528352604090810190525092915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a7b576120508161186c565b8061206257506001600160a01b038316155b156120805760405163db70dad160e01b815260040160405180910390fd5b5f546001600160a01b031615610a7b575f5460405163657711f560e11b81523360048201526001600160a01b0385811660248301528481166044830152606482018490529091169063caee23ea906084015f6040518083038186803b1580156120e7575f5ffd5b505afa1580156110a8573d5f5f3e3d5ffd5b638b78c6d8600c52825f526020600c2080548381178361211a575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f60208284031215612160575f5ffd5b81356001600160e01b0319811681146110d0575f5ffd5b6001600160a01b038116811461092f575f5ffd5b8035610fe981612177565b80356001600160601b0381168114610fe9575f5ffd5b5f5f604083850312156121bd575f5ffd5b82356121c881612177565b91506121d660208401612196565b90509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f60208284031215612224575f5ffd5b5035919050565b5f5f6040838503121561223c575f5ffd5b823561224781612177565b946020939093013593505050565b803563ffffffff81168114610fe9575f5ffd5b5f5f83601f840112612278575f5ffd5b5081356001600160401b0381111561228e575f5ffd5b6020830191508360208260051b85010111156122a8575f5ffd5b9250929050565b80356001600160801b0381168114610fe9575f5ffd5b5f5f5f5f5f5f60a087890312156122da575f5ffd5b6122e387612255565b955060208701356001600160401b038111156122fd575f5ffd5b61230989828a01612268565b909650945050604087013561231d81612177565b9250606087013561232d81612177565b915061233b608088016122af565b90509295509295509295565b5f5f5f5f6040858703121561235a575f5ffd5b84356001600160401b0381111561236f575f5ffd5b61237b87828801612268565b90955093505060208501356001600160401b03811115612399575f5ffd5b6123a587828801612268565b95989497509550505050565b5f5f5f606084860312156123c3575f5ffd5b83356123ce81612177565b925060208401356123de81612177565b929592945050506040919091013590565b5f5f60408385031215612400575f5ffd5b50508035926020909101359150565b5f6020828403121561241f575f5ffd5b81356110d081612177565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156124665761246661242a565b604052919050565b5f6001600160401b038211156124865761248661242a565b50601f01601f191660200190565b5f82601f8301126124a3575f5ffd5b81356124b66124b18261246e565b61243e565b8181528460208386010111156124ca575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f5f5f60e0888a0312156124fc575f5ffd5b873561250781612177565b965060208801356001600160401b03811115612521575f5ffd5b61252d8a828b01612494565b96505060408801356001600160401b03811115612548575f5ffd5b6125548a828b01612494565b95505060608801356001600160401b0381111561256f575f5ffd5b61257b8a828b01612494565b94505061258a6080890161218b565b925061259860a0890161218b565b91506125a660c08901612196565b905092959891949750929550565b5f5f5f606084860312156125c6575f5ffd5b83356125d181612177565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561261d5783518352602093840193909201916001016125ff565b509095945050505050565b5f5f60408385031215612639575f5ffd5b823561264481612177565b915060208301358015158114612658575f5ffd5b809150509250929050565b5f5f5f5f5f60808688031215612677575f5ffd5b853561268281612177565b9450602086013561269281612177565b93506040860135925060608601356001600160401b038111156126b3575f5ffd5b8601601f810188136126c3575f5ffd5b80356001600160401b038111156126d8575f5ffd5b8860208284010111156126e9575f5ffd5b959894975092955050506020019190565b5f6020828403121561270a575f5ffd5b81356001600160401b0381111561271f575f5ffd5b61272b84828501612494565b949350505050565b5f5f60408385031215612744575f5ffd5b823561274f81612177565b9150602083013561265881612177565b5f5f5f5f5f60608688031215612773575f5ffd5b85356001600160401b03811115612788575f5ffd5b61279488828901612268565b90965094505060208601356001600160401b038111156127b2575f5ffd5b6127be88828901612268565b90945092506127d19050604087016122af565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610a5d57610a5d6127dd565b80820180821115610a5d57610a5d6127dd565b600181811c9082168061282f57607f821691505b60208210810361284d57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612877575f5ffd5b81516110d081612177565b8183525f6001600160fb1b03831115612899575f5ffd5b8260051b80836020870137939093016020019392505050565b63ffffffff881681526001600160a01b038716602082015260c0604082018190525f906128e29083018789612882565b6001600160a01b0395861660608401529390941660808201526001600160801b039190911660a09091015295945050505050565b601f821115610a7b57805f5260205f20601f840160051c8101602085101561293b5750805b601f840160051c820191505b818110156112d4575f8155600101612947565b81516001600160401b038111156129735761297361242a565b61298781612981845461281b565b84612916565b6020601f8211600181146129b9575f83156129a25750848201515b5f19600385901b1c1916600184901b1784556112d4565b5f84815260208120601f198516915b828110156129e857878501518255602094850194600190920191016129c8565b5084821015612a0557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f60208284031215612a24575f5ffd5b81516001600160401b03811115612a39575f5ffd5b8201601f81018413612a49575f5ffd5b8051612a576124b18261246e565b818152856020838501011115612a6b575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b6001600160a01b038816815260a0602082018190525f90612aac908301888a612882565b828103604084015285815286906020015f5b87811015612ae95763ffffffff612ad484612255565b16825260209283019290910190600101612abe565b506001600160a01b03861660608501526001600160801b03851660808501529150612b119050565b98975050505050505050565b5f60208284031215612b2d575f5ffd5b5051919050565b5f60018201612b4557612b456127dd565b506001019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d64736f6c634300081c0033

Deployed Bytecode

0x6080604052600436106102e3575f3560e01c8063529470e81161018f578063a9fc664e116100db578063e985e9c511610094578063f2fde38b1161006e578063f2fde38b1461089a578063f7dec9b4146108ad578063fd4fe8a8146108c0578063fee81cf4146108df576102e3565b8063e985e9c51461083c578063ed06167814610870578063f04e283e14610887576102e3565b8063a9fc664e1461078e578063b1dae618146107ad578063b45a3c0e146107cc578063b88d4fde146107eb578063c87b56dd146107fe578063e0df5b6f1461081d576102e3565b8063715018a6116101485780638da5cb5b116101225780638da5cb5b1461071757806395d89b411461072f57806399a2557a14610743578063a22cb4651461076f576102e3565b8063715018a6146106d05780637347ebb9146106d85780638528e8d3146106f8576102e3565b8063529470e81461063b57806354d1f13d1461065457806358456fb51461065c5780636352211e14610673578063703199701461069257806370a08231146106b1576102e3565b80631c10893f1161024e57806329e38d5e1161020757806342842e0e116101e157806342842e0e146105c157806342966c68146105d45780634a4ee7b1146105f3578063514e62fc14610606576102e3565b806329e38d5e146105345780632a55205a146105525780632de9480714610590576102e3565b80631c10893f146104895780631cd64df41461049c5780631de26e8e146104d157806321f36509146104e557806323b872dd14610519578063256929621461052c576102e3565b8063098144d4116102a0578063098144d4146103ea5780630a212100146104065780630c756a78146104195780630d705df61461043c578063156c2c3214610463578063183a4f6e14610476576102e3565b806301ddc8bf146102f957806301ffc9a71461034957806302fa7c471461037857806306fdde0314610397578063081812fc146103b8578063095ea7b3146103d7575b3480156102ee575f5ffd5b506102f7610910565b005b348015610304575f5ffd5b5061032c7f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b81565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610354575f5ffd5b50610368610363366004612150565b6109e3565b6040519015158152602001610340565b348015610383575f5ffd5b506102f76103923660046121ac565b610a63565b3480156103a2575f5ffd5b506103ab610a80565b60405161034091906121df565b3480156103c3575f5ffd5b5061032c6103d2366004612214565b610b10565b6102f76103e536600461222b565b610b4b565b3480156103f5575f5ffd5b505f546001600160a01b031661032c565b6102f76104143660046122c5565b610b5a565b348015610424575f5ffd5b5061042e61200081565b604051908152602001610340565b348015610447575f5ffd5b506040805163657711f560e11b81526001602082015201610340565b61042e610471366004612347565b610daa565b6102f7610484366004612214565b610dc1565b6102f761049736600461222b565b610dcb565b3480156104a7575f5ffd5b506103686104b636600461222b565b638b78c6d8600c9081525f9290925260209091205481161490565b3480156104dc575f5ffd5b506102f7610ddd565b3480156104f0575f5ffd5b5061032c6104ff366004612214565b60016020525f90815260409020546001600160a01b031681565b6102f76105273660046123b1565b610dff565b6102f7610e94565b34801561053f575f5ffd5b505f5461032c906001600160a01b031681565b34801561055d575f5ffd5b5061057161056c3660046123ef565b610ee0565b604080516001600160a01b039093168352602083019190915201610340565b34801561059b575f5ffd5b5061042e6105aa36600461240f565b638b78c6d8600c9081525f91909152602090205490565b6102f76105cf3660046123b1565b610f33565b3480156105df575f5ffd5b506102f76105ee366004612214565b610f5f565b6102f761060136600461222b565b610f80565b348015610611575f5ffd5b5061036861062036600461222b565b638b78c6d8600c9081525f9290925260209091205416151590565b348015610646575f5ffd5b5061042e6504000000000081565b6102f7610f92565b348015610667575f5ffd5b5061042e600160581b81565b34801561067e575f5ffd5b5061032c61068d366004612214565b610fcb565b34801561069d575f5ffd5b5060055461032c906001600160a01b031681565b3480156106bc575f5ffd5b5061042e6106cb36600461240f565b610fee565b6102f7611026565b3480156106e3575f5ffd5b5060055461036890600160a01b900460ff1681565b348015610703575f5ffd5b506102f76107123660046124e6565b611039565b348015610722575f5ffd5b50638b78c6d8195461032c565b34801561073a575f5ffd5b506103ab6110b1565b34801561074e575f5ffd5b5061076261075d3660046125b4565b6110c0565b60405161034091906125e6565b34801561077a575f5ffd5b506102f7610789366004612628565b6110d7565b348015610799575f5ffd5b506102f76107a836600461240f565b61112a565b3480156107b8575f5ffd5b506102f76107c7366004612214565b61119a565b3480156107d7575f5ffd5b506103686107e6366004612214565b611277565b6102f76107f9366004612663565b611281565b348015610809575f5ffd5b506103ab610818366004612214565b6112db565b348015610828575f5ffd5b506102f76108373660046126fa565b611439565b348015610847575f5ffd5b50610368610856366004612733565b601c52670a5a2e7a000000006008525f526030600c205490565b34801561087b575f5ffd5b5061042e600160451b81565b6102f761089536600461240f565b611494565b6102f76108a836600461240f565b6114ce565b61042e6108bb36600461275f565b6114f4565b3480156108cb575f5ffd5b506102f76108da36600461240f565b61152c565b3480156108ea575f5ffd5b5061042e6108f936600461240f565b63389a75e1600c9081525f91909152602090205490565b5f3560e01c6340c10f198190036109325761092f6004356024356115b8565b50565b806392772833036109ca57336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b16146109865760405163db70dad160e01b815260040160405180910390fd5b6044356024355f5b828110156109c4576109bc6109b66109a78360206127f1565b6109b2906064612808565b3590565b8361164c565b60010161098e565b50505050565b604051631e085ca760e11b815260040160405180910390fd5b5f6001600160e01b03198216635a2d1e0760e11b1480610a245750610a24826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b80610a425750632a55205a60e083901c9081146301ffc9a791909114175b80610a5d57506001600160e01b03198216632483248360e11b145b92915050565b600160581b610a71816116fc565b610a7b8383611720565b505050565b606060038054610a8f9061281b565b80601f0160208091040260200160405190810160405280929190818152602001828054610abb9061281b565b8015610b065780601f10610add57610100808354040283529160200191610b06565b820191905f5260205f20905b815481529060010190602001808311610ae957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610b415763ceea21b65f526004601cfd5b6001015492915050565b610b56338383611769565b5050565b5f5b84811015610c8f57610b8633878784818110610b7a57610b7a612853565b90506020020135611803565b610ba35760405163096dcfe360e31b815260040160405180910390fd5b610bc4868683818110610bb857610bb8612853565b9050602002013561186c565b15610be257604051635a8181f760e01b815260040160405180910390fd5b600554600160a01b900460ff16610c1457610c14868683818110610c0857610c08612853565b9050602002013561188e565b610c36868683818110610c2957610c29612853565b905060200201355f611898565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a1611868683818110610c6957610c69612853565b90506020020135604051610c7f91815260200190565b60405180910390a1600101610b5c565b5060405163f174883560e01b81523060048201525f907f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b03169063f174883590602401602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d189190612867565b90507f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b031663c9df81673489848a8a8a8a8a6040518963ffffffff1660e01b8152600401610d7397969594939291906128b2565b5f604051808303818588803b158015610d8a575f5ffd5b505af1158015610d9c573d5f5f3e3d5ffd5b505050505050505050505050565b5f610db8858585855f6118c7565b95945050505050565b61092f33826119f8565b610dd3611a03565b610b568282611a1d565b612000610de9816116fc565b506005805460ff60a01b1916600160a01b179055565b6001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b163303610e89576001610e56825f818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b6001600160601b031603610e7d576040516305b166a360e41b815260040160405180910390fd5b610a7b5f848484611a29565b610a7b838383611b23565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f82815268aa4ec00224afccfdb76020526040812054606081901c91906127109083610f13576020515490508060601c93505b606084901b18845f19829004811182023d3d3e9396930204935090915050565b610f3e838383610dff565b813b15610a7b57610a7b83838360405180602001604052805f815250611c14565b610f688161186c565b15610f765761092f8161188e565b61092f3382611c95565b610f88611a03565b610b5682826119f8565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b5f610fd582611d53565b905080610fe95763ceea21b65f526004601cfd5b919050565b5f8161100157638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b61102e611a03565b6110375f611d7a565b565b6002611045858261295a565b506003611052878261295a565b50600461105f868261295a565b50600580546001600160a01b0319166001600160a01b03851617905561108487611dc0565b5f80546001600160a01b0319166001600160a01b0384161790556110a88782611720565b50505050505050565b606060048054610a8f9061281b565b60606110cd848484611e18565b90505b9392505050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b600160451b611138816116fc565b5f80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91015b60405180910390a1505050565b336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b16146111e35760405163db70dad160e01b815260040160405180910390fd5b5f818152600160205260409020546001600160a01b031680611203575050565b5f828152600160205260409081902080546001600160a01b03191690555163163b5cc360e31b8152600481018390526001600160a01b0382169063b1dae618906024015f604051808303815f87803b15801561125d575f5ffd5b505af115801561126f573d5f5f3e3d5ffd5b505050505050565b5f610a5d8261186c565b61128c858585610dff565b833b156112d4576112d485858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1492505050565b5050505050565b6060611304825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6113215760405163677510db60e11b815260040160405180910390fd5b6005546001600160a01b03161561139f5760055460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd906024015f60405180830381865afa158015611378573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a5d9190810190612a14565b610a5d600280546113af9061281b565b80601f01602080910402602001604051908101604052809291908181526020018280546113db9061281b565b80156114265780601f106113fd57610100808354040283529160200191611426565b820191905f5260205f20905b81548152906001019060200180831161140957829003601f168201915b505050505061143484611f7a565b611fbc565b65040000000000611449816116fc565b6002611455838261295a565b50604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91015b60405180910390a15050565b61149c611a03565b63389a75e1600c52805f526020600c2080544211156114c257636f5e88185f526004601cfd5b5f905561092f81611d7a565b6114d6611a03565b8060601b6114eb57637448fbae5f526004601cfd5b61092f81611d7a565b5f5f61150387878787876118c7565b5f81815260016020526040902080546001600160a01b0319163317905591505095945050505050565b6504000000000061153c816116fc565b600580546001600160a01b0319166001600160a01b0384169081179091556040517faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a03905f90a2604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9101611488565b6115c35f8383612017565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b156115fe5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026116325767ea553b3401336cea841560021b526004601cfd5b905580825f5f516020612b4d5f395f51905f528138a45050565b6116558261186c565b156116e3575f61166483611d53565b90506001600160a01b0381166116835761167e82846115b8565b6116a8565b806001600160a01b0316826001600160a01b0316146116a8576116a85f828486611a29565b6116b3836001611898565b6040518381527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429060200161118d565b6040516305b166a360e41b815260040160405180910390fd5b638b78c6d8600c52335f52806020600c20541661092f576382b429005f526004601cfd5b6001600160601b0316612710808211156117415763350a88b35f526004601cfd5b8260601b806117575763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816117ac5763ceea21b65f526004601cfd5b8185148515176117d057815f526030600c20546117d057634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919360019216806118465763ceea21b65f526004601cfd5b80851461186457805f526030600c2054611864578160010154851492505b505092915050565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b61092f5f82611c95565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60405163f174883560e01b81523060048201525f9081906001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b169063f174883590602401602060405180830381865afa15801561192d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119519190612867565b90507f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b031663fe084c8f34838a8a8a8a338b6040518963ffffffff1660e01b81526004016119ac9796959493929190612a88565b60206040518083038185885af11580156119c8573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119ed9190612b1d565b979650505050505050565b610b5682825f6120f9565b638b78c6d819543314611037576382b429005f526004601cfd5b610b56828260016120f9565b611a34838383612017565b5f8181526001600160a01b03948516673ec412a9852d173d60c11b8117601c526020909120820182018054919594851694938416938216918286148302611a8a5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082871486881417871517611ab9576030600c2054611ab957634b6e7f185f526004601cfd5b8215611ac6575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611b075767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a450505050565b611b2e838383612017565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302611b7f5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417611bab576030600c2054611bab57634b6e7f185f526004601cfd5b8215611bb8575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611bf95767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a4505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611c5b578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611c7c573d15611c7c573d5f843e3d83fd5b508060e01b82511461126f5763d1a57ed65f526004601cfd5b5f611c9f82610fcb565b9050611cac815f84612017565b505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919382169182611cef5763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611d1c576030600c2054611d1c57634b6e7f185f526004601cfd5b8015611d29575f83600101555b5082189055601c600c2080545f19019055815f825f516020612b4d5f395f51905f528238a4505050565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b638b78c6d819805415611dda57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60605f611e2485610fee565b90505f80826001600160401b03811115611e4057611e4061242a565b604051908082528060200260200182016040528015611e69578160200160208202803683370190505b509050855b858111611edf57876001600160a01b0316611e8882611d53565b6001600160a01b031603611ecd5780828481518110611ea957611ea9612853565b602090810291909101015260018084019385900301611ecd575092506110d0915050565b80611ed781612b34565b915050611e6e565b505f826001600160401b03811115611ef957611ef961242a565b604051908082528060200260200182016040528015611f22578160200160208202803683370190505b5090505f5b83811015611f6e57828181518110611f4157611f41612853565b6020026020010151828281518110611f5b57611f5b612853565b6020908102919091010152600101611f27565b50979650505050505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a900480611f93575050819003601f19909101908152919050565b6040518251601f19906020810182165b8581015184820152820180611fcc575083518184018360208301165b8681015182820152840180611fe85750505f910183810160208101929092528352604090810190525092915050565b336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b1614610a7b576120508161186c565b8061206257506001600160a01b038316155b156120805760405163db70dad160e01b815260040160405180910390fd5b5f546001600160a01b031615610a7b575f5460405163657711f560e11b81523360048201526001600160a01b0385811660248301528481166044830152606482018490529091169063caee23ea906084015f6040518083038186803b1580156120e7575f5ffd5b505afa1580156110a8573d5f5f3e3d5ffd5b638b78c6d8600c52825f526020600c2080548381178361211a575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f60208284031215612160575f5ffd5b81356001600160e01b0319811681146110d0575f5ffd5b6001600160a01b038116811461092f575f5ffd5b8035610fe981612177565b80356001600160601b0381168114610fe9575f5ffd5b5f5f604083850312156121bd575f5ffd5b82356121c881612177565b91506121d660208401612196565b90509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f60208284031215612224575f5ffd5b5035919050565b5f5f6040838503121561223c575f5ffd5b823561224781612177565b946020939093013593505050565b803563ffffffff81168114610fe9575f5ffd5b5f5f83601f840112612278575f5ffd5b5081356001600160401b0381111561228e575f5ffd5b6020830191508360208260051b85010111156122a8575f5ffd5b9250929050565b80356001600160801b0381168114610fe9575f5ffd5b5f5f5f5f5f5f60a087890312156122da575f5ffd5b6122e387612255565b955060208701356001600160401b038111156122fd575f5ffd5b61230989828a01612268565b909650945050604087013561231d81612177565b9250606087013561232d81612177565b915061233b608088016122af565b90509295509295509295565b5f5f5f5f6040858703121561235a575f5ffd5b84356001600160401b0381111561236f575f5ffd5b61237b87828801612268565b90955093505060208501356001600160401b03811115612399575f5ffd5b6123a587828801612268565b95989497509550505050565b5f5f5f606084860312156123c3575f5ffd5b83356123ce81612177565b925060208401356123de81612177565b929592945050506040919091013590565b5f5f60408385031215612400575f5ffd5b50508035926020909101359150565b5f6020828403121561241f575f5ffd5b81356110d081612177565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156124665761246661242a565b604052919050565b5f6001600160401b038211156124865761248661242a565b50601f01601f191660200190565b5f82601f8301126124a3575f5ffd5b81356124b66124b18261246e565b61243e565b8181528460208386010111156124ca575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f5f5f60e0888a0312156124fc575f5ffd5b873561250781612177565b965060208801356001600160401b03811115612521575f5ffd5b61252d8a828b01612494565b96505060408801356001600160401b03811115612548575f5ffd5b6125548a828b01612494565b95505060608801356001600160401b0381111561256f575f5ffd5b61257b8a828b01612494565b94505061258a6080890161218b565b925061259860a0890161218b565b91506125a660c08901612196565b905092959891949750929550565b5f5f5f606084860312156125c6575f5ffd5b83356125d181612177565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561261d5783518352602093840193909201916001016125ff565b509095945050505050565b5f5f60408385031215612639575f5ffd5b823561264481612177565b915060208301358015158114612658575f5ffd5b809150509250929050565b5f5f5f5f5f60808688031215612677575f5ffd5b853561268281612177565b9450602086013561269281612177565b93506040860135925060608601356001600160401b038111156126b3575f5ffd5b8601601f810188136126c3575f5ffd5b80356001600160401b038111156126d8575f5ffd5b8860208284010111156126e9575f5ffd5b959894975092955050506020019190565b5f6020828403121561270a575f5ffd5b81356001600160401b0381111561271f575f5ffd5b61272b84828501612494565b949350505050565b5f5f60408385031215612744575f5ffd5b823561274f81612177565b9150602083013561265881612177565b5f5f5f5f5f60608688031215612773575f5ffd5b85356001600160401b03811115612788575f5ffd5b61279488828901612268565b90965094505060208601356001600160401b038111156127b2575f5ffd5b6127be88828901612268565b90945092506127d19050604087016122af565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610a5d57610a5d6127dd565b80820180821115610a5d57610a5d6127dd565b600181811c9082168061282f57607f821691505b60208210810361284d57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612877575f5ffd5b81516110d081612177565b8183525f6001600160fb1b03831115612899575f5ffd5b8260051b80836020870137939093016020019392505050565b63ffffffff881681526001600160a01b038716602082015260c0604082018190525f906128e29083018789612882565b6001600160a01b0395861660608401529390941660808201526001600160801b039190911660a09091015295945050505050565b601f821115610a7b57805f5260205f20601f840160051c8101602085101561293b5750805b601f840160051c820191505b818110156112d4575f8155600101612947565b81516001600160401b038111156129735761297361242a565b61298781612981845461281b565b84612916565b6020601f8211600181146129b9575f83156129a25750848201515b5f19600385901b1c1916600184901b1784556112d4565b5f84815260208120601f198516915b828110156129e857878501518255602094850194600190920191016129c8565b5084821015612a0557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f60208284031215612a24575f5ffd5b81516001600160401b03811115612a39575f5ffd5b8201601f81018413612a49575f5ffd5b8051612a576124b18261246e565b818152856020838501011115612a6b575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b6001600160a01b038816815260a0602082018190525f90612aac908301888a612882565b828103604084015285815286906020015f5b87811015612ae95763ffffffff612ad484612255565b16825260209283019290910190600101612abe565b506001600160a01b03861660608501526001600160801b03851660808501529150612b119050565b98975050505050505050565b5f60208284031215612b2d575f5ffd5b5051919050565b5f60018201612b4557612b456127dd565b506001019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d64736f6c634300081c0033

Deployed Bytecode Sourcemap

134:364:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3931:17:5;:15;:17::i;:::-;134:364:6;2463:48:5;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;178:32:13;;;160:51;;148:2;133:18;2463:48:5;;;;;;;;12113:297;;;;;;;;;;-1:-1:-1;12113:297:5;;;;;:::i;:::-;;:::i;:::-;;;678:14:13;;671:22;653:41;;641:2;626:18;12113:297:5;513:187:13;10534:163:5;;;;;;;;;;-1:-1:-1;10534:163:5;;;;;:::i;:::-;;:::i;13089:90::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;8099:532:3:-;;;;;;;;;;-1:-1:-1;8099:532:3;;;;;:::i;:::-;;:::i;8925:119::-;;;;;;:::i;:::-;;:::i;14240:105:5:-;;;;;;;;;;-1:-1:-1;14295:7:5;14321:17;-1:-1:-1;;;;;14321:17:5;14240:105;;7856:882;;;;;;:::i;:::-;;:::i;2548:59::-;;;;;;;;;;;;13430:7:1;2548:59:5;;;;;4259:25:13;;;4247:2;4232:18;2548:59:5;4113:177:13;14622:189:5;;;;;;;;;;-1:-1:-1;14622:189:5;;;-1:-1:-1;;;4461:52:13;;14800:4:5;4544:2:13;4529:18;;4522:50;4434:18;14622:189:5;4295:283:13;6184:148:5;;;;;;:::i;:::-;;:::i;10291:109:1:-;;;;;;:::i;:::-;;:::i;9752:123::-;;;;;;:::i;:::-;;:::i;11342:139::-;;;;;;;;;;-1:-1:-1;11342:139:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;11421:4;10962:18;;;;11062:4;11046:21;;;11040:28;11444:21;;:30;;11342:139;8953:114:5;;;;;;;;;;;;;:::i;2976:64::-;;;;;;;;;;-1:-1:-1;2976:64:5;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2976:64:5;;;5567:359;;;;;;:::i;:::-;;:::i;9021:617:0:-;;;:::i;2883:32:5:-;;;;;;;;;;-1:-1:-1;2883:32:5;;;;-1:-1:-1;;;;;2883:32:5;;;3179:1058:2;;;;;;;;;;-1:-1:-1;3179:1058:2;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;6778:32:13;;;6760:51;;6842:2;6827:18;;6820:34;;;;6733:18;3179:1058:2;6586:274:13;10731:353:1;;;;;;;;;;-1:-1:-1;10731:353:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;10791:13;10962:18;;;;11062:4;11046:21;;11040:28;;10731:353;13705:198:3;;;;;;:::i;:::-;;:::i;10959:174:5:-;;;;;;;;;;-1:-1:-1;10959:174:5;;;;;:::i;:::-;;:::i;10020:125:1:-;;;;;;:::i;:::-;;:::i;11146:134::-;;;;;;;;;;-1:-1:-1;11146:134:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;11224:4;10962:18;;;;11062:4;11046:21;;;11040:28;11247:21;:26;;;11146:134;2613:56:5;;;;;;;;;;;;14880:7:1;2613:56:5;;9720:456:0;;;:::i;2747:55:5:-;;;;;;;;;;;;-1:-1:-1;;;2747:55:5;;6957:332:3;;;;;;;;;;-1:-1:-1;6957:332:3;;;;;:::i;:::-;;:::i;3502:31:5:-;;;;;;;;;;-1:-1:-1;3502:31:5;;;;-1:-1:-1;;;;;3502:31:5;;;7433:533:3;;;;;;;;;;-1:-1:-1;7433:533:3;;;;;:::i;:::-;;:::i;8762:100:0:-;;;:::i;3620:29:5:-;;;;;;;;;;-1:-1:-1;3620:29:5;;;;-1:-1:-1;;;3620:29:5;;;;;;4495:679;;;;;;;;;;-1:-1:-1;4495:679:5;;;;;:::i;:::-;;:::i;11408:182:0:-;;;;;;;;;;-1:-1:-1;;;11556:18:0;11408:182;;13307:94:5;;;;;;;;;;;;;:::i;13881:170::-;;;;;;;;;;-1:-1:-1;13881:170:5;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;9667:726:3:-;;;;;;;;;;-1:-1:-1;9667:726:3;;;;;:::i;:::-;;:::i;10033:289:5:-;;;;;;;;;;-1:-1:-1;10033:289:5;;;;;:::i;:::-;;:::i;11259:338::-;;;;;;;;;;-1:-1:-1;11259:338:5;;;;;:::i;:::-;;:::i;11756:102::-;;;;;;;;;;-1:-1:-1;11756:102:5;;;;;:::i;:::-;;:::i;14406:249:3:-;;;;;;:::i;:::-;;:::i;12643:324:5:-;;;;;;;;;;-1:-1:-1;12643:324:5;;;;;:::i;:::-;;:::i;9240:175::-;;;;;;;;;;-1:-1:-1;9240:175:5;;;;;:::i;:::-;;:::i;9135:392:3:-;;;;;;;;;;-1:-1:-1;9135:392:3;;;;;:::i;:::-;9355:4;9348:22;9396:31;9390:4;9383:45;9255:11;9441:19;9505:4;9499;9489:21;9483:28;;9135:392;2675:66:5;;;;;;;;;;;;-1:-1:-1;;;2675:66:5;;10363:708:0;;;;;;:::i;:::-;;:::i;8348:349::-;;;;;;:::i;:::-;;:::i;6961:300:5:-;;;;;;:::i;:::-;;:::i;9569:261::-;;;;;;;;;;-1:-1:-1;9569:261:5;;;;;:::i;:::-;;:::i;11693:435:0:-;;;;;;;;;;-1:-1:-1;11693:435:0;;;;;:::i;:::-;11963:19;11957:4;11950:33;;;11812:14;11996:26;;;;12106:4;12090:21;;12084:28;;11693:435;17979:783:5;18025:18;17937:20;18069:3;18046:26;18101:10;18087:24;;;18083:673;;18210:65;18246:4;17937:20;18269:4;17937:20;18210:5;:65::i;:::-;18015:747;17979:783::o;18083:673::-;18296:10;18310;18296:24;18292:464;;18340:10;-1:-1:-1;;;;;18354:23:5;18340:37;;18336:67;;18386:17;;-1:-1:-1;;;18386:17:5;;;;;;;;;;;18336:67;18457:4;17937:20;18528:4;17937:20;18418:22;18550:133;18574:14;18570:1;:18;18550:133;;;18613:55;18626:28;18647:6;:1;18651:2;18647:6;:::i;:::-;18640:13;;:4;:13;:::i;:::-;17937:20;;17775:198;18626:28;18656:11;18613:12;:55::i;:::-;18590:3;;18550:133;;;;18322:371;;18015:747;17979:783::o;18292:464::-;18720:25;;-1:-1:-1;;;18720:25:5;;;;;;;;;;;12113:297;12207:4;-1:-1:-1;;;;;;12230:41:5;;-1:-1:-1;;;12230:41:5;;:82;;;12275:37;12300:11;15177:10:3;15042:3;15038:21;;;;15171:17;;;15196:10;15190:17;;15168:40;15216:10;15210:17;;;15165:63;;14864:380;12275:37:5;12230:136;;;-1:-1:-1;3054:10:2;2930:3;2926:21;;;3048:17;;;3035:10;3029:17;;;;3026:40;12328:38:5;12230:173;;;-1:-1:-1;;;;;;;12370:33:5;;-1:-1:-1;;;12370:33:5;12230:173;12223:180;12113:297;-1:-1:-1;;12113:297:5:o;10534:163::-;-1:-1:-1;;;11897:18:1;11909:5;11897:11;:18::i;:::-;10648:42:5::1;10667:8;10677:12;10648:18;:42::i;:::-;10534:163:::0;;;:::o;13089:90::-;13135:13;13167:5;13160:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13089:90;:::o;8099:532:3:-;8161:14;8266:2;8260:4;8253:16;-1:-1:-1;;;8289:4:3;8282:38;8386:4;8380;8370:21;8366:2;8362:30;8358:2;8354:39;8430:13;8424:20;8420:2;8416:29;8406:158;;8478:10;8472:4;8465:24;8545:4;8539;8532:18;8406:158;8597:1;8593:21;8587:28;;8099:532;-1:-1:-1;;8099:532:3:o;8925:119::-;9004:33;9013:10;9025:7;9034:2;9004:8;:33::i;:::-;8925:119;;:::o;7856:882:5:-;8068:9;8063:386;8083:19;;;8063:386;;;8128:43;8147:10;8159:8;;8168:1;8159:11;;;;;;;:::i;:::-;;;;;;;8128:18;:43::i;:::-;8123:78;;8180:21;;-1:-1:-1;;;8180:21:5;;;;;;;;;;;8123:78;8219:20;8227:8;;8236:1;8227:11;;;;;;;:::i;:::-;;;;;;;8219:7;:20::i;:::-;8215:46;;;8248:13;;-1:-1:-1;;;8248:13:5;;;;;;;;;;;8215:46;8281:17;;-1:-1:-1;;;8281:17:5;;;;8276:75;;8318:18;8324:8;;8333:1;8324:11;;;;;;;:::i;:::-;;;;;;;8318:5;:18::i;:::-;8365:34;8379:8;;8388:1;8379:11;;;;;;;:::i;:::-;;;;;;;3172:1;8365:13;:34::i;:::-;8419:19;8426:8;;8435:1;8426:11;;;;;;;:::i;:::-;;;;;;;8419:19;;;;4259:25:13;;4247:2;4232:18;;4113:177;8419:19:5;;;;;;;;8104:3;;8063:386;;;-1:-1:-1;8491:60:5;;-1:-1:-1;;;8491:60:5;;8545:4;8491:60;;;160:51:13;8459:29:5;;8499:23;-1:-1:-1;;;;;8491:45:5;;;;133:18:13;;8491:60:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8459:92;;8569:23;-1:-1:-1;;;;;8561:37:5;;8606:9;8630:6;8638:21;8661:8;;8671:11;8684:15;8701:20;8561:170;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8053:685;7856:882;;;;;;:::o;6184:148::-;6275:7;6301:24;6307:8;;6317:4;;6323:1;6301:5;:24::i;:::-;6294:31;6184:148;-1:-1:-1;;;;;6184:148:5:o;10291:109:1:-;10362:31;10375:10;10387:5;10362:12;:31::i;9752:123::-;12517:13:0;:11;:13::i;:::-;9844:24:1::1;9856:4;9862:5;9844:11;:24::i;8953:114:5:-:0;13430:7:1;11897:18;11909:5;11897:11;:18::i;:::-;-1:-1:-1;9036:17:5::1;:24:::0;;-1:-1:-1;;;;9036:24:5::1;-1:-1:-1::0;;;9036:24:5::1;::::0;;8953:114::o;5567:359::-;-1:-1:-1;;;;;5684:23:5;5670:37;:10;:37;5666:254;;3214:1;5727:22;5741:7;18232:13:3;18323:16;;;-1:-1:-1;;;18359:4:3;18352:38;18460:4;18444:21;;18436:30;;18428:39;18422:46;18417:3;18413:56;;18166:319;5727:22:5;-1:-1:-1;;;;;5727:34:5;;5723:63;;5770:16;;-1:-1:-1;;;5770:16:5;;;;;;;;;;;5723:63;5801:40;5819:1;5823:4;5829:2;5833:7;5801:9;:40::i;5666:254::-;5872:37;5891:4;5897:2;5901:7;5872:18;:37::i;9021:617:0:-;9114:15;7972:9;-1:-1:-1;;;;;9132:46:0;:15;:46;9114:64;;9346:19;9340:4;9333:33;9396:8;9390:4;9383:22;9452:7;9445:4;9439;9429:21;9422:38;9599:8;9552:45;9549:1;9546;9541:67;9248:374;9021:617::o;3179:1058:2:-;3297:16;3470:21;;;3517:25;3511:4;3504:39;3592:4;3576:21;;3570:28;3627:2;3623:15;;;;3297:16;2531:5;;3623:15;3651:124;;3711:4;3705:11;3699:18;3689:28;;3754:6;3750:2;3746:15;3734:27;;3651:124;3844:2;3840:17;;;3828:30;3797:9;-1:-1:-1;;4144:14:2;;;4138:21;;4131:29;;4113:16;4095;4080:81;3179:1058;;4195:9;;4191:30;;-1:-1:-1;3179:1058:2;;-1:-1:-1;;3179:1058:2:o;13705:198:3:-;13802:26;13815:4;13821:2;13825;13802:12;:26::i;:::-;38367:14;;13838:58;;;13856:40;13879:4;13885:2;13889;13856:40;;;;;;;;;;;;:22;:40::i;10959:174:5:-;11013:16;11021:7;11013;:16::i;:::-;11009:118;;;11045:14;11051:7;11045:5;:14::i;11009:118::-;11090:26;11096:10;11108:7;11090:5;:26::i;10020:125:1:-;12517:13:0;:11;:13::i;:::-;10113:25:1::1;10126:4;10132:5;10113:12;:25::i;9720:456:0:-:0;9922:19;9916:4;9909:33;9968:8;9962:4;9955:22;10020:1;10013:4;10007;9997:21;9990:32;10151:8;10105:44;10102:1;10099;10094:66;9720:456::o;6957:332:3:-;7015:14;7050:12;7059:2;7050:8;:12::i;:::-;7041:21;;7148:6;7138:135;;7187:10;7181:4;7174:24;7254:4;7248;7241:18;7138:135;6957:332;;;:::o;7433:533::-;7496:14;7656:5;7646:143;;7694:10;7688:4;7681:24;7770:4;7764;7757:18;7646:143;-1:-1:-1;;;7809:4:3;7802:38;7866:5;7860:4;7853:19;7929:20;7921:4;7915;7905:21;7899:28;7895:55;7885:65;;7433:533;;;:::o;8762:100:0:-;12517:13;:11;:13::i;:::-;8834:21:::1;8852:1;8834:9;:21::i;:::-;8762:100::o:0;4495:679:5:-;4867:13;:29;4883:13;4867;:29;:::i;:::-;-1:-1:-1;4906:5:5;:23;4914:15;4906:5;:23;:::i;:::-;-1:-1:-1;4939:7:5;:27;4949:17;4939:7;:27;:::i;:::-;-1:-1:-1;4976:16:5;:36;;-1:-1:-1;;;;;;4976:36:5;-1:-1:-1;;;;;4976:36:5;;;;;5022:31;5039:13;5022:16;:31::i;:::-;5064:17;:38;;-1:-1:-1;;;;;;5064:38:5;-1:-1:-1;;;;;5064:38:5;;;;;5112:55;5131:13;5146:20;5112:18;:55::i;:::-;4495:679;;;;;;;:::o;13307:94::-;13355:13;13387:7;13380:14;;;;;:::i;13881:170::-;13973:16;14008:36;14025:5;14032;14039:4;14008:16;:36::i;:::-;14001:43;;13881:170;;;;;;:::o;9667:726:3:-;9882:10;9875:18;9868:26;9854:40;;9991:8;9985:4;9978:22;10026:31;10020:4;10013:45;10084:8;10078:4;10071:22;10136:10;10129:4;10123;10113:21;10106:41;10221:10;10215:4;10208:24;10366:8;10362:2;10358:17;10354:2;10350:26;10340:8;10305:33;10299:4;10293;10288:89;9667:726;;:::o;10033:289:5:-;-1:-1:-1;;;11897:18:1;11909:5;11897:11;:18::i;:::-;10153:20:5::1;10176:17:::0;;-1:-1:-1;;;;;10203:38:5;;::::1;-1:-1:-1::0;;;;;;10203:38:5;::::1;::::0;::::1;::::0;;;10257:58:::1;::::0;;10176:17;;;::::1;18147:51:13::0;;;18229:2;18214:18;;18207:60;;;;10257:58:5::1;::::0;18120:18:13;10257:58:5::1;;;;;;;;10143:179;10033:289:::0;;:::o;11259:338::-;11321:10;-1:-1:-1;;;;;11335:23:5;11321:37;;11317:67;;11367:17;;-1:-1:-1;;;11367:17:5;;;;;;;;;;;11317:67;11395:22;11420:15;;;:9;:15;;;;;;-1:-1:-1;;;;;11420:15:5;;11445:41;;11479:7;11259:338;:::o;11445:41::-;11503:15;;;;:9;:15;;;;;;;11496:22;;-1:-1:-1;;;;;;11496:22:5;;;11529:61;-1:-1:-1;;;11529:61:5;;;;;4259:25:13;;;-1:-1:-1;;;;;11529:55:5;;;;;4232:18:13;;11529:61:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11307:290;11259:338;:::o;11756:102::-;11812:4;11835:16;11843:7;11835;:16::i;14406:249:3:-;14552:26;14565:4;14571:2;14575;14552:12;:26::i;:::-;38367:14;;14588:60;;;14606:42;14629:4;14635:2;14639;14643:4;;14606:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14606:22:3;;-1:-1:-1;;;14606:42:3:i;:::-;14406:249;;;;;:::o;12643:324:5:-;12703:13;12733:11;12741:2;15636:11:3;15725:16;;;-1:-1:-1;;;15761:4:3;15754:38;15875:4;15859:21;;15851:30;;15843:39;15837:46;15833:2;15829:55;15822:63;15815:71;;15576:326;12733:11:5;12728:44;;12753:19;;-1:-1:-1;;;12753:19:5;;;;;;;;;;;12728:44;12787:16;;-1:-1:-1;;;;;12787:16:5;:30;12783:105;;12847:16;;12840:37;;-1:-1:-1;;;12840:37:5;;;;;4259:25:13;;;-1:-1:-1;;;;;12847:16:5;;;;12840:33;;4232:18:13;;12840:37:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;12840:37:5;;;;;;;;;;;;:::i;12783:105::-;12905:55;12922:13;12905:55;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12937:22;12956:2;12937:18;:22::i;:::-;12905:16;:55::i;9240:175::-;14880:7:1;11897:18;11909:5;11897:11;:18::i;:::-;9332:13:5::1;:19;9348:3:::0;9332:13;:19:::1;:::i;:::-;-1:-1:-1::0;9367:41:5::1;::::0;;9387:1:::1;19152:25:13::0;;-1:-1:-1;;19208:2:13;19193:18;;19186:34;9367:41:5::1;::::0;19125:18:13;9367:41:5::1;;;;;;;;9240:175:::0;;:::o;10363:708:0:-;12517:13;:11;:13::i;:::-;10597:19:::1;10591:4;10584:33;10643:12;10637:4;10630:26;10705:4;10699;10689:21;10811:12;10805:19;10792:11;10789:36;10786:157;;;10857:10;10851:4;10844:24;10924:4;10918;10911:18;10786:157;11020:1;10999:23:::0;;11041::::1;11051:12:::0;11041:9:::1;:23::i;8348:349::-:0;12517:13;:11;:13::i;:::-;8520:8:::1;8516:2;8512:17;8502:150;;8562:10;8556:4;8549:24;8633:4;8627;8620:18;8502:150;8671:19;8681:8;8671:9;:19::i;6961:300:5:-:0;7116:7;7139:12;7154:39;7160:8;;7170:4;;7176:16;7154:5;:39::i;:::-;7204:15;;;;:9;:15;;;;;:28;;-1:-1:-1;;;;;;7204:28:5;7222:10;7204:28;;;7139:54;-1:-1:-1;;6961:300:5;;;;;;;:::o;9569:261::-;14880:7:1;11897:18;11909:5;11897:11;:18::i;:::-;9677:16:5::1;:36:::0;;-1:-1:-1;;;;;;9677:36:5::1;-1:-1:-1::0;;;;;9677:36:5;::::1;::::0;;::::1;::::0;;;9729:38:::1;::::0;::::1;::::0;-1:-1:-1;;9729:38:5::1;9782:41;::::0;;9802:1:::1;19152:25:13::0;;-1:-1:-1;;19208:2:13;19193:18;;19186:34;9782:41:5::1;::::0;19125:18:13;9782:41:5::1;18970:256:13::0;19609:1653:3;19675:40;19704:1;19708:2;19712;19675:20;:40::i;:::-;19853:2;19849;19845:11;19841:2;19837:20;19831:26;;19923:2;19917:4;19910:16;-1:-1:-1;;;19946:4:3;19939:38;20043:4;20037;20027:21;20023:2;20019:30;20015:2;20011:39;20092:13;20086:20;20181:15;20177:2;20173:24;20170:146;;;20229:10;20223:4;20216:24;20297:4;20291;20284:18;20170:146;20389:23;;20367:46;;20502:4;20495:16;;;20563:4;20557;20547:21;20614:18;;20634:1;20610:26;20786:20;20763:44;;20755:53;;20745:268;;20937:18;20931:2;20924:10;20921:1;20917:18;20910:46;20990:4;20984;20977:18;20745:268;21030:38;;21194:2;21190;21187:1;-1:-1:-1;;;;;;;;;;;21187:1:3;21142:10;21137:60;8925:119;;:::o;15514:587:5:-;15597:16;15605:7;15597;:16::i;:::-;15593:502;;;15629:13;15645:17;15654:7;15645:8;:17::i;:::-;15629:33;-1:-1:-1;;;;;;15751:19:5;;15747:200;;15790:27;15796:11;15809:7;15790:5;:27::i;:::-;15747:200;;;15857:5;-1:-1:-1;;;;;15842:20:5;:11;-1:-1:-1;;;;;15842:20:5;;15838:109;;15882:50;15900:1;15904:5;15911:11;15924:7;15882:9;:50::i;:::-;15961:32;15975:7;3214:1;15961:13;:32::i;:::-;16013:17;;4259:25:13;;;16013:17:5;;4247:2:13;4232:18;16013:17:5;4113:177:13;15593:502:5;16068:16;;-1:-1:-1;;;16068:16:5;;;;;;;;;;;4659:554:1;4844:15;4838:4;4831:29;4886:8;4880:4;4873:22;5077:5;5069:4;5063;5053:21;5047:28;5043:40;5033:164;;5116:10;5110:4;5103:24;5178:4;5172;5165:18;4464:715:2;-1:-1:-1;;;;;4692:32:2;2531:5;4740:32;;;4737:151;;;4804:10;4798:4;4791:24;4869:4;4863;4856:18;4737:151;4923:8;4919:2;4915:17;4955:6;4945:146;;4994:10;4988:4;4981:24;5072:4;5066;5059:18;4945:146;5138:24;;;5111:25;5104:59;-1:-1:-1;;4464:715:2:o;29039:1442:3:-;29222:1;29218:6;29214:2;29210:15;29269:7;29253:14;29249:28;29238:39;;29316:2;29300:14;29296:23;29290:29;;29389:2;29383:4;29376:16;29447:2;-1:-1:-1;;;29418:32:3;29412:4;29405:46;29517:4;29511;29501:21;29497:2;29493:30;29489:2;29485:39;29576:13;29570:20;29554:14;29550:41;29537:54;;29665:5;29655:134;;29703:10;29697:4;29690:24;29770:4;29764;29757:18;29655:134;29972:5;29968:2;29965:13;29960:2;29953:10;29950:29;29940:280;;30012:5;30006:4;29999:19;30067:4;30061;30051:21;30045:28;30035:171;;30110:10;30104:4;30097:24;30183:4;30177;30170:18;30035:171;30314:1;30310:21;30303:38;;;30462:2;30333:7;30446:5;30419:25;30413:4;30401:10;30396:69;;29039:1442;;;:::o;26907:1160::-;27027:11;27273:16;;;-1:-1:-1;;;;;27195:25:3;;;-1:-1:-1;;;27315:37:3;;27309:4;27302:51;27419:4;27403:21;;;27395:30;;27387:39;;27468:20;;27195:25;;27130:1;;27452:38;;27554:134;;27602:10;27596:4;27589:24;27669:4;27663;27656:18;27554:134;27773:5;27764:7;27761:18;27751:300;;27812:5;27806:4;27799:19;27938:4;27932;27922:21;27916:28;27906:131;;28003:13;28000:1;27996:21;27990:28;27981:7;27978:41;27968:51;;27906:131;27751:300;;26907:1160;;;;:::o;17545:119:5:-;17602:4;18323:16:3;;;-1:-1:-1;;;18359:4:3;18352:38;18460:4;18444:21;;18436:30;;18428:39;18422:46;18417:3;18413:56;17625:32:5;;17545:119::o;23961:82:3:-;24015:21;24029:1;24033:2;24015:5;:21::i;18689:432::-;18844:2;18838:4;18831:16;-1:-1:-1;;;18867:4:3;18860:38;18964:4;18958;18948:21;18944:2;18940:30;18936:2;18932:39;19004:13;18998:20;19094:6;19089:3;19085:16;19078:5;19074:28;19069:3;19065:38;19057:6;19053:51;19038:13;19031:74;;;18689:432;;:::o;14817:419:5:-;15003:60;;-1:-1:-1;;;15003:60:5;;15057:4;15003:60;;;160:51:13;14948:7:5;;;;-1:-1:-1;;;;;15011:23:5;15003:45;;;;133:18:13;;15003:60:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14971:92;;15088:23;-1:-1:-1;;;;;15080:37:5;;15125:9;15149:21;15172:8;;15182:7;;15191:10;15203:16;15080:149;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15073:156;14817:419;-1:-1:-1;;;;;;;14817:419:5:o;4468:117:1:-;4546:32;4559:4;4565:5;4572;4546:12;:32::i;7292:355:0:-;-1:-1:-1;;7498:18:0;7488:8;7485:32;7475:156;;7550:10;7544:4;7537:24;7612:4;7606;7599:18;4217:115:1;4294:31;4307:4;4313:5;4320:4;4294:12;:31::i;32278:3007:3:-;32374:34;32395:4;32401:2;32405;32374:20;:34::i;:::-;32558:1;32744:16;;;-1:-1:-1;;;;;32668:23:3;;;-1:-1:-1;;;32786:32:3;;32780:4;32773:46;32885:4;32869:21;;;32861:30;;32853:39;;32928:20;;32668:23;;32582:25;;;;32626:23;;;;32974:36;;;33126:15;;;33115:27;;33105:229;;33266:18;33257:5;33250:13;33247:1;33243:21;33236:49;33315:4;33309;33302:18;33105:229;33437:4;33431;33424:18;33495:13;33492:1;33488:21;33482:28;33459:51;;33726:15;33722:2;33719:23;33712:4;33708:2;33705:12;33702:41;33697:2;33690:10;33687:57;33677:292;;33800:4;33794;33784:21;33778:28;33768:183;;33847:10;33841:4;33834:24;33924:4;33918;33911:18;33768:183;34044:15;34041:55;;;34092:1;34076:13;34073:1;34069:21;34062:32;34041:55;34208:13;;;34187:35;34165:58;;-1:-1:-1;34341:4:3;34335;34325:21;;;34391:22;;-1:-1:-1;;34387:30:3;34363:55;;-1:-1:-1;34509:16:3;;;34563:21;34632:20;;34415:1;34628:28;34808:20;34783:46;;34775:55;;34765:270;;34959:18;34953:2;34946:10;34943:1;34939:18;34932:46;35012:4;35006;34999:18;34765:270;35052:42;;35223:2;35219;35213:4;-1:-1:-1;;;;;;;;;;;35180:4:3;35168:10;35163:63;32278:3007;;;;:::o;10748:2886::-;10841:34;10862:4;10868:2;10872;10841:20;:34::i;:::-;11025:1;11169:16;;;-1:-1:-1;;;11240:8:3;11211:38;11205:4;11198:52;11316:4;11300:21;;11292:30;;11284:39;;11359:20;;-1:-1:-1;;;;;11049:25:3;;;;11093:23;;;;11405:36;;;11284:39;11557:15;;;11546:27;;11536:229;;11697:18;11688:5;11681:13;11678:1;11674:21;11667:49;11746:4;11740;11733:18;11536:229;11868:4;11862;11855:18;11926:13;11923:1;11919:21;11913:28;11890:51;;12076:15;12066:8;12063:29;12056:4;12046:8;12043:18;12040:53;12030:288;;12149:4;12143;12133:21;12127:28;12117:183;;12196:10;12190:4;12183:24;12273:4;12267;12260:18;12117:183;12393:15;12390:55;;;12441:1;12425:13;12422:1;12418:21;12411:32;12390:55;12557:13;;;12536:35;12514:58;;-1:-1:-1;12690:4:3;12684;12674:21;;;12740:22;;-1:-1:-1;;12736:30:3;12712:55;;-1:-1:-1;12858:16:3;;;12912:21;12981:20;;12764:1;12977:28;13157:20;13132:46;;13124:55;;13114:270;;13308:18;13302:2;13295:10;13292:1;13288:18;13281:46;13361:4;13355;13348:18;13114:270;13401:42;;13572:2;13568;13562:4;-1:-1:-1;;;;;;;;;;;13529:4:3;13517:10;13512:63;10534:163:5;;;:::o;38588:1370:3:-;38825:4;38819:11;38875:10;38908:24;38905:1;38898:35;38967:8;38960:4;38957:1;38953:12;38946:30;39075:4;39071:2;39067:13;39063:2;39059:22;39052:4;39049:1;39045:12;39038:44;39116:2;39109:4;39106:1;39102:12;39095:24;39153:4;39146;39143:1;39139:12;39132:26;39186:4;39180:11;39225:1;39218:4;39215:1;39211:12;39204:23;39243:1;39240:71;;;39306:1;39299:4;39296:1;39292:12;39289:1;39282:4;39276;39272:15;39269:1;39262:5;39251:57;39247:62;39240:71;39427:4;39424:1;39417:4;39414:1;39410:12;39403:4;39400:1;39396:12;39393:1;39389:2;39382:5;39377:55;39367:313;;39455:16;39452:214;;;39583:16;39577:4;39574:1;39559:41;39631:16;39628:1;39621:27;39452:214;39367:313;39776:24;39771:3;39767:34;39763:1;39757:8;39754:48;39744:198;;39835:10;39829:4;39822:24;39923:4;39917;39910:18;24332:2127;24398:13;24414:11;24422:2;24414:7;:11::i;:::-;24398:27;;24435:43;24456:5;24471:1;24475:2;24435:20;:43::i;:::-;-1:-1:-1;24680:4:3;24673:16;;;-1:-1:-1;;;;;24600:20:3;;;-1:-1:-1;;;24715:32:3;;24709:4;24702:46;24814:4;24798:21;;;24790:30;;24782:39;;24857:20;;24600;;24980:33;;;;25077:134;;25125:10;25119:4;25112:24;25192:4;25186;25179:18;25077:134;25305:5;25299:4;25292:19;25364:13;25361:1;25357:21;25351:28;25596:15;25592:2;25589:23;25581:5;25577:2;25574:13;25571:42;25566:2;25559:10;25556:58;25546:293;;25670:4;25664;25654:21;25648:28;25638:183;;25717:10;25711:4;25704:24;25794:4;25788;25781:18;25638:183;25914:15;25911:55;;;25962:1;25946:13;25943:1;25939:21;25932:32;25911:55;-1:-1:-1;26047:27:3;;26025:50;;26190:4;26184;26174:21;26236:18;;-1:-1:-1;;26232:26:3;26212:47;;26388:2;-1:-1:-1;26068:5:3;-1:-1:-1;;;;;;;;;;;;26333:10:3;26328:63;10534:163:5;;;:::o;16037:323:3:-;16098:14;16190:16;;;-1:-1:-1;;;16226:4:3;16219:38;16334:4;16318:21;;16310:30;;16302:39;16296:46;-1:-1:-1;;;;;16280:64:3;;16037:323::o;6145:1089:0:-;-1:-1:-1;;6579:16:0;;-1:-1:-1;;;;;6427:26:0;;;;;;6539:38;6536:1;;6528:78;6703:16;;6698:3;6694:26;6681:40;;6663:59;;18015:747:5;17979:783::o;4883:1190:0:-;-1:-1:-1;;5125:9:0;5119:16;5116:150;;;5171:10;5165:4;5158:24;5243:4;5237;5230:18;5116:150;-1:-1:-1;;;;;5339:26:0;;;5462:16;;5457:3;5453:26;5440:40;;5422:59;;;5339:26;5607:1;5567:38;5607:1;;5556:63;18015:747:5;17979:783::o;16107:900::-;16200:16;16228:22;16253:16;16263:5;16253:9;:16::i;:::-;16228:41;-1:-1:-1;16279:18:5;;16228:41;-1:-1:-1;;;;;16339:29:5;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16339:29:5;-1:-1:-1;16311:57:5;-1:-1:-1;16396:5:5;16379:336;16408:4;16403:1;:9;16379:336;;16452:5;-1:-1:-1;;;;;16437:20:5;:11;16446:1;16437:8;:11::i;:::-;-1:-1:-1;;;;;16437:20:5;;16433:272;;16500:1;16477:8;16486:10;16477:20;;;;;;;;:::i;:::-;;;;;;;;;;:24;16552:12;;;;;16605:28;;;;16601:90;;-1:-1:-1;16664:8:5;-1:-1:-1;16657:15:5;;-1:-1:-1;;16657:15:5;16601:90;16414:3;;;;:::i;:::-;;;;16379:336;;;;16827:23;16867:10;-1:-1:-1;;;;;16853:25:5;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16853:25:5;-1:-1:-1;16827:51:5;-1:-1:-1;16893:9:5;16888:89;16912:10;16908:1;:14;16888:89;;;16955:8;16964:1;16955:11;;;;;;;;:::i;:::-;;;;;;;16943:6;16950:1;16943:9;;;;;;;;:::i;:::-;;;;;;;;;;:23;16924:3;;16888:89;;;-1:-1:-1;16994:6:5;16107:900;-1:-1:-1;;;;;;;16107:900:5:o;3513:1560:4:-;3569:20;4020:4;4013;4007:11;4003:22;3993:32;;4063:4;4055:6;4051:17;4045:4;4038:31;4117:1;4109:6;4102:17;4182:6;4276:1;4272:6;4485:5;4467:398;4526:14;;;;4716:2;4730;4720:13;;4712:22;4526:14;4696:39;4770:2;4760:13;;4826:25;4467:398;4826:25;-1:-1:-1;;4887:16:4;;;-1:-1:-1;;4926:17:4;;;5019;;;4926;3513:1560;-1:-1:-1;3513:1560:4:o;38748:1214::-;38963:4;38957:11;39024:8;;-1:-1:-1;;38990:9:4;39129:4;39119:15;;39115:23;;39100:207;39193:9;;;39187:16;39171:14;;;39164:40;39226:9;;39271:22;39100:207;39271:22;39104:36;39338:1;39332:8;39379:4;39371:6;39367:17;39488:1;39481:4;39475;39471:15;39467:23;39452:207;39545:9;;;39539:16;39523:14;;;39516:40;39578:9;;39623:22;39452:207;39623:22;-1:-1:-1;;39786:1:4;39688:15;;39728:32;;;39744:4;39728:32;;39773:15;;;;39839:24;;39910:15;;;;39897:29;;-1:-1:-1;39736:6:4;38748:1214;-1:-1:-1;;38748:1214:4:o;17090:449:5:-;17200:10;-1:-1:-1;;;;;17214:23:5;17200:37;;17196:337;;17257:16;17265:7;17257;:16::i;:::-;:38;;;-1:-1:-1;;;;;;17277:18:5;;;17257:38;17253:101;;;17322:17;;-1:-1:-1;;;17322:17:5;;;;;;;;;;;17253:101;17401:1;17372:17;-1:-1:-1;;;;;17372:17:5;:31;17368:155;;17442:17;;17423:85;;-1:-1:-1;;;17423:85:5;;17478:10;17423:85;;;20878:51:13;-1:-1:-1;;;;;20965:32:13;;;20945:18;;;20938:60;21034:32;;;21014:18;;;21007:60;21083:18;;;21076:34;;;17442:17:5;;;;17423:54;;20850:19:13;;17423:85:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3116:967:1;3282:15;3276:4;3269:29;3324:4;3318;3311:18;3374:4;3368;3358:21;3452:8;3446:15;3559:5;3550:7;3547:18;3803:2;3793:62;;-1:-1:-1;3833:19:1;;;3820:33;;3793:62;3927:7;3917:8;3910:25;4059:7;4051:4;4045:11;4041:2;4037:20;4005:30;4002:1;3999;3994:73;;;;3116:967;;;:::o;222:286:13:-;280:6;333:2;321:9;312:7;308:23;304:32;301:52;;;349:1;346;339:12;301:52;375:23;;-1:-1:-1;;;;;;427:32:13;;417:43;;407:71;;474:1;471;464:12;705:131;-1:-1:-1;;;;;780:31:13;;770:42;;760:70;;826:1;823;816:12;841:134;909:20;;938:31;909:20;938:31;:::i;980:179::-;1047:20;;-1:-1:-1;;;;;1096:38:13;;1086:49;;1076:77;;1149:1;1146;1139:12;1164:319;1231:6;1239;1292:2;1280:9;1271:7;1267:23;1263:32;1260:52;;;1308:1;1305;1298:12;1260:52;1347:9;1334:23;1366:31;1391:5;1366:31;:::i;:::-;1416:5;-1:-1:-1;1440:37:13;1473:2;1458:18;;1440:37;:::i;:::-;1430:47;;1164:319;;;;;:::o;1488:418::-;1637:2;1626:9;1619:21;1600:4;1669:6;1663:13;1712:6;1707:2;1696:9;1692:18;1685:34;1771:6;1766:2;1758:6;1754:15;1749:2;1738:9;1734:18;1728:50;1827:1;1822:2;1813:6;1802:9;1798:22;1794:31;1787:42;1897:2;1890;1886:7;1881:2;1873:6;1869:15;1865:29;1854:9;1850:45;1846:54;1838:62;;;1488:418;;;;:::o;1911:226::-;1970:6;2023:2;2011:9;2002:7;1998:23;1994:32;1991:52;;;2039:1;2036;2029:12;1991:52;-1:-1:-1;2084:23:13;;1911:226;-1:-1:-1;1911:226:13:o;2142:367::-;2210:6;2218;2271:2;2259:9;2250:7;2246:23;2242:32;2239:52;;;2287:1;2284;2277:12;2239:52;2326:9;2313:23;2345:31;2370:5;2345:31;:::i;:::-;2395:5;2473:2;2458:18;;;;2445:32;;-1:-1:-1;;;2142:367:13:o;2514:163::-;2581:20;;2641:10;2630:22;;2620:33;;2610:61;;2667:1;2664;2657:12;2682:367;2745:8;2755:6;2809:3;2802:4;2794:6;2790:17;2786:27;2776:55;;2827:1;2824;2817:12;2776:55;-1:-1:-1;2850:20:13;;-1:-1:-1;;;;;2882:30:13;;2879:50;;;2925:1;2922;2915:12;2879:50;2962:4;2954:6;2950:17;2938:29;;3022:3;3015:4;3005:6;3002:1;2998:14;2990:6;2986:27;2982:38;2979:47;2976:67;;;3039:1;3036;3029:12;2976:67;2682:367;;;;;:::o;3054:188::-;3122:20;;-1:-1:-1;;;;;3171:46:13;;3161:57;;3151:85;;3232:1;3229;3222:12;3247:861;3368:6;3376;3384;3392;3400;3408;3461:3;3449:9;3440:7;3436:23;3432:33;3429:53;;;3478:1;3475;3468:12;3429:53;3501:28;3519:9;3501:28;:::i;:::-;3491:38;;3580:2;3569:9;3565:18;3552:32;-1:-1:-1;;;;;3599:6:13;3596:30;3593:50;;;3639:1;3636;3629:12;3593:50;3678:70;3740:7;3731:6;3720:9;3716:22;3678:70;:::i;:::-;3767:8;;-1:-1:-1;3652:96:13;-1:-1:-1;;3852:2:13;3837:18;;3824:32;3865:31;3824:32;3865:31;:::i;:::-;3915:5;-1:-1:-1;3972:2:13;3957:18;;3944:32;3985:33;3944:32;3985:33;:::i;:::-;4037:7;-1:-1:-1;4063:39:13;4097:3;4082:19;;4063:39;:::i;:::-;4053:49;;3247:861;;;;;;;;:::o;4583:767::-;4704:6;4712;4720;4728;4781:2;4769:9;4760:7;4756:23;4752:32;4749:52;;;4797:1;4794;4787:12;4749:52;4837:9;4824:23;-1:-1:-1;;;;;4862:6:13;4859:30;4856:50;;;4902:1;4899;4892:12;4856:50;4941:70;5003:7;4994:6;4983:9;4979:22;4941:70;:::i;:::-;5030:8;;-1:-1:-1;4915:96:13;-1:-1:-1;;5118:2:13;5103:18;;5090:32;-1:-1:-1;;;;;5134:32:13;;5131:52;;;5179:1;5176;5169:12;5131:52;5218:72;5282:7;5271:8;5260:9;5256:24;5218:72;:::i;:::-;4583:767;;;;-1:-1:-1;5309:8:13;-1:-1:-1;;;;4583:767:13:o;5722:508::-;5799:6;5807;5815;5868:2;5856:9;5847:7;5843:23;5839:32;5836:52;;;5884:1;5881;5874:12;5836:52;5923:9;5910:23;5942:31;5967:5;5942:31;:::i;:::-;5992:5;-1:-1:-1;6049:2:13;6034:18;;6021:32;6062:33;6021:32;6062:33;:::i;:::-;5722:508;;6114:7;;-1:-1:-1;;;6194:2:13;6179:18;;;;6166:32;;5722:508::o;6235:346::-;6303:6;6311;6364:2;6352:9;6343:7;6339:23;6335:32;6332:52;;;6380:1;6377;6370:12;6332:52;-1:-1:-1;;6425:23:13;;;6545:2;6530:18;;;6517:32;;-1:-1:-1;6235:346:13:o;6865:247::-;6924:6;6977:2;6965:9;6956:7;6952:23;6948:32;6945:52;;;6993:1;6990;6983:12;6945:52;7032:9;7019:23;7051:31;7076:5;7051:31;:::i;7117:127::-;7178:10;7173:3;7169:20;7166:1;7159:31;7209:4;7206:1;7199:15;7233:4;7230:1;7223:15;7249:275;7320:2;7314:9;7385:2;7366:13;;-1:-1:-1;;7362:27:13;7350:40;;-1:-1:-1;;;;;7405:34:13;;7441:22;;;7402:62;7399:88;;;7467:18;;:::i;:::-;7503:2;7496:22;7249:275;;-1:-1:-1;7249:275:13:o;7529:187::-;7578:4;-1:-1:-1;;;;;7603:6:13;7600:30;7597:56;;;7633:18;;:::i;:::-;-1:-1:-1;7699:2:13;7678:15;-1:-1:-1;;7674:29:13;7705:4;7670:40;;7529:187::o;7721:488::-;7764:5;7817:3;7810:4;7802:6;7798:17;7794:27;7784:55;;7835:1;7832;7825:12;7784:55;7875:6;7862:20;7906:53;7922:36;7951:6;7922:36;:::i;:::-;7906:53;:::i;:::-;7984:6;7975:7;7968:23;8038:3;8031:4;8022:6;8014;8010:19;8006:30;8003:39;8000:59;;;8055:1;8052;8045:12;8000:59;8120:6;8113:4;8105:6;8101:17;8094:4;8085:7;8081:18;8068:59;8176:1;8147:20;;;8169:4;8143:31;8136:42;;;;8151:7;7721:488;-1:-1:-1;;;7721:488:13:o;8214:1113::-;8356:6;8364;8372;8380;8388;8396;8404;8457:3;8445:9;8436:7;8432:23;8428:33;8425:53;;;8474:1;8471;8464:12;8425:53;8513:9;8500:23;8532:31;8557:5;8532:31;:::i;:::-;8582:5;-1:-1:-1;8638:2:13;8623:18;;8610:32;-1:-1:-1;;;;;8654:30:13;;8651:50;;;8697:1;8694;8687:12;8651:50;8720;8762:7;8753:6;8742:9;8738:22;8720:50;:::i;:::-;8710:60;;;8823:2;8812:9;8808:18;8795:32;-1:-1:-1;;;;;8842:8:13;8839:32;8836:52;;;8884:1;8881;8874:12;8836:52;8907;8951:7;8940:8;8929:9;8925:24;8907:52;:::i;:::-;8897:62;;;9012:2;9001:9;8997:18;8984:32;-1:-1:-1;;;;;9031:8:13;9028:32;9025:52;;;9073:1;9070;9063:12;9025:52;9096;9140:7;9129:8;9118:9;9114:24;9096:52;:::i;:::-;9086:62;;;9167:39;9201:3;9190:9;9186:19;9167:39;:::i;:::-;9157:49;;9225:39;9259:3;9248:9;9244:19;9225:39;:::i;:::-;9215:49;;9283:38;9316:3;9305:9;9301:19;9283:38;:::i;:::-;9273:48;;8214:1113;;;;;;;;;;:::o;9332:487::-;9409:6;9417;9425;9478:2;9466:9;9457:7;9453:23;9449:32;9446:52;;;9494:1;9491;9484:12;9446:52;9533:9;9520:23;9552:31;9577:5;9552:31;:::i;:::-;9602:5;9680:2;9665:18;;9652:32;;-1:-1:-1;9783:2:13;9768:18;;;9755:32;;9332:487;-1:-1:-1;;;9332:487:13:o;9824:611::-;10014:2;10026:21;;;10096:13;;9999:18;;;10118:22;;;9966:4;;10197:15;;;10171:2;10156:18;;;9966:4;10240:169;10254:6;10251:1;10248:13;10240:169;;;10315:13;;10303:26;;10358:2;10384:15;;;;10349:12;;;;10276:1;10269:9;10240:169;;;-1:-1:-1;10426:3:13;;9824:611;-1:-1:-1;;;;;9824:611:13:o;10440:416::-;10505:6;10513;10566:2;10554:9;10545:7;10541:23;10537:32;10534:52;;;10582:1;10579;10572:12;10534:52;10621:9;10608:23;10640:31;10665:5;10640:31;:::i;:::-;10690:5;-1:-1:-1;10747:2:13;10732:18;;10719:32;10789:15;;10782:23;10770:36;;10760:64;;10820:1;10817;10810:12;10760:64;10843:7;10833:17;;;10440:416;;;;;:::o;10861:983::-;10958:6;10966;10974;10982;10990;11043:3;11031:9;11022:7;11018:23;11014:33;11011:53;;;11060:1;11057;11050:12;11011:53;11099:9;11086:23;11118:31;11143:5;11118:31;:::i;:::-;11168:5;-1:-1:-1;11225:2:13;11210:18;;11197:32;11238:33;11197:32;11238:33;:::i;:::-;11290:7;-1:-1:-1;11370:2:13;11355:18;;11342:32;;-1:-1:-1;11451:2:13;11436:18;;11423:32;-1:-1:-1;;;;;11467:30:13;;11464:50;;;11510:1;11507;11500:12;11464:50;11533:22;;11586:4;11578:13;;11574:27;-1:-1:-1;11564:55:13;;11615:1;11612;11605:12;11564:55;11655:2;11642:16;-1:-1:-1;;;;;11673:6:13;11670:30;11667:50;;;11713:1;11710;11703:12;11667:50;11758:7;11753:2;11744:6;11740:2;11736:15;11732:24;11729:37;11726:57;;;11779:1;11776;11769:12;11726:57;10861:983;;;;-1:-1:-1;10861:983:13;;-1:-1:-1;;;11810:2:13;11802:11;;11832:6;10861:983::o;11849:322::-;11918:6;11971:2;11959:9;11950:7;11946:23;11942:32;11939:52;;;11987:1;11984;11977:12;11939:52;12027:9;12014:23;-1:-1:-1;;;;;12052:6:13;12049:30;12046:50;;;12092:1;12089;12082:12;12046:50;12115;12157:7;12148:6;12137:9;12133:22;12115:50;:::i;:::-;12105:60;11849:322;-1:-1:-1;;;;11849:322:13:o;12176:388::-;12244:6;12252;12305:2;12293:9;12284:7;12280:23;12276:32;12273:52;;;12321:1;12318;12311:12;12273:52;12360:9;12347:23;12379:31;12404:5;12379:31;:::i;:::-;12429:5;-1:-1:-1;12486:2:13;12471:18;;12458:32;12499:33;12458:32;12499:33;:::i;12569:841::-;12699:6;12707;12715;12723;12731;12784:2;12772:9;12763:7;12759:23;12755:32;12752:52;;;12800:1;12797;12790:12;12752:52;12840:9;12827:23;-1:-1:-1;;;;;12865:6:13;12862:30;12859:50;;;12905:1;12902;12895:12;12859:50;12944:70;13006:7;12997:6;12986:9;12982:22;12944:70;:::i;:::-;13033:8;;-1:-1:-1;12918:96:13;-1:-1:-1;;13121:2:13;13106:18;;13093:32;-1:-1:-1;;;;;13137:32:13;;13134:52;;;13182:1;13179;13172:12;13134:52;13221:72;13285:7;13274:8;13263:9;13259:24;13221:72;:::i;:::-;13312:8;;-1:-1:-1;13195:98:13;-1:-1:-1;13366:38:13;;-1:-1:-1;13400:2:13;13385:18;;13366:38;:::i;:::-;13356:48;;12569:841;;;;;;;;:::o;13415:127::-;13476:10;13471:3;13467:20;13464:1;13457:31;13507:4;13504:1;13497:15;13531:4;13528:1;13521:15;13547:168;13620:9;;;13651;;13668:15;;;13662:22;;13648:37;13638:71;;13689:18;;:::i;13720:125::-;13785:9;;;13806:10;;;13803:36;;;13819:18;;:::i;13850:380::-;13929:1;13925:12;;;;13972;;;13993:61;;14047:4;14039:6;14035:17;14025:27;;13993:61;14100:2;14092:6;14089:14;14069:18;14066:38;14063:161;;14146:10;14141:3;14137:20;14134:1;14127:31;14181:4;14178:1;14171:15;14209:4;14206:1;14199:15;14063:161;;13850:380;;;:::o;14235:127::-;14296:10;14291:3;14287:20;14284:1;14277:31;14327:4;14324:1;14317:15;14351:4;14348:1;14341:15;14367:251;14437:6;14490:2;14478:9;14469:7;14465:23;14461:32;14458:52;;;14506:1;14503;14496:12;14458:52;14538:9;14532:16;14557:31;14582:5;14557:31;:::i;14623:311::-;14711:19;;;14693:3;-1:-1:-1;;;;;14742:31:13;;14739:51;;;14786:1;14783;14776:12;14739:51;14822:6;14819:1;14815:14;14874:8;14867:5;14860:4;14855:3;14851:14;14838:45;14903:18;;;;14923:4;14899:29;;14623:311;-1:-1:-1;;;14623:311:13:o;15063:781::-;15402:10;15390:23;;15372:42;;-1:-1:-1;;;;;15450:32:13;;15445:2;15430:18;;15423:60;15519:3;15514:2;15499:18;;15492:31;;;-1:-1:-1;;15540:74:13;;15594:19;;15586:6;15578;15540:74;:::i;:::-;-1:-1:-1;;;;;15650:32:13;;;15645:2;15630:18;;15623:60;15720:32;;;;15714:3;15699:19;;15692:61;-1:-1:-1;;;;;15790:47:13;;;;15670:3;15769:19;;;15762:76;15720:32;15532:82;-1:-1:-1;;;;;15063:781:13:o;15975:518::-;16077:2;16072:3;16069:11;16066:421;;;16113:5;16110:1;16103:16;16157:4;16154:1;16144:18;16227:2;16215:10;16211:19;16208:1;16204:27;16198:4;16194:38;16263:4;16251:10;16248:20;16245:47;;;-1:-1:-1;16286:4:13;16245:47;16341:2;16336:3;16332:12;16329:1;16325:20;16319:4;16315:31;16305:41;;16396:81;16414:2;16407:5;16404:13;16396:81;;;16473:1;16459:16;;16440:1;16429:13;16396:81;;16669:1299;16795:3;16789:10;-1:-1:-1;;;;;16814:6:13;16811:30;16808:56;;;16844:18;;:::i;:::-;16873:97;16963:6;16923:38;16955:4;16949:11;16923:38;:::i;:::-;16917:4;16873:97;:::i;:::-;17019:4;17050:2;17039:14;;17067:1;17062:649;;;;17755:1;17772:6;17769:89;;;-1:-1:-1;17824:19:13;;;17818:26;17769:89;-1:-1:-1;;16626:1:13;16622:11;;;16618:24;16614:29;16604:40;16650:1;16646:11;;;16601:57;17871:81;;17032:930;;17062:649;15922:1;15915:14;;;15959:4;15946:18;;-1:-1:-1;;17098:20:13;;;17216:222;17230:7;17227:1;17224:14;17216:222;;;17312:19;;;17306:26;17291:42;;17419:4;17404:20;;;;17372:1;17360:14;;;;17246:12;17216:222;;;17220:3;17466:6;17457:7;17454:19;17451:201;;;17527:19;;;17521:26;-1:-1:-1;;17610:1:13;17606:14;;;17622:3;17602:24;17598:37;17594:42;17579:58;17564:74;;17451:201;-1:-1:-1;;;;17698:1:13;17682:14;;;17678:22;17665:36;;-1:-1:-1;16669:1299:13:o;18278:687::-;18358:6;18411:2;18399:9;18390:7;18386:23;18382:32;18379:52;;;18427:1;18424;18417:12;18379:52;18460:9;18454:16;-1:-1:-1;;;;;18485:6:13;18482:30;18479:50;;;18525:1;18522;18515:12;18479:50;18548:22;;18601:4;18593:13;;18589:27;-1:-1:-1;18579:55:13;;18630:1;18627;18620:12;18579:55;18663:2;18657:9;18688:53;18704:36;18733:6;18704:36;:::i;18688:53::-;18764:6;18757:5;18750:21;18812:7;18807:2;18798:6;18794:2;18790:15;18786:24;18783:37;18780:57;;;18833:1;18830;18823:12;18780:57;18881:6;18876:2;18872;18868:11;18863:2;18856:5;18852:14;18846:42;18933:1;18908:18;;;18928:2;18904:27;18897:38;;;;18912:5;18278:687;-1:-1:-1;;;;18278:687:13:o;19231:1082::-;-1:-1:-1;;;;;19590:32:13;;19572:51;;19610:3;19654:2;19639:18;;19632:31;;;-1:-1:-1;;19686:74:13;;19740:19;;19732:6;19724;19686:74;:::i;:::-;19796:22;;;19791:2;19776:18;;19769:50;19854:22;;;19930:6;;19904:2;19892:15;19954:1;19964:198;19978:6;19975:1;19972:13;19964:198;;;20070:10;20043:25;20061:6;20043:25;:::i;:::-;20039:42;20027:55;;20111:2;20137:15;;;;20102:12;;;;20000:1;19993:9;19964:198;;;-1:-1:-1;;;;;;20218:32:13;;20213:2;20198:18;;20191:60;-1:-1:-1;;;;;15005:46:13;;20302:3;20287:19;;14993:59;20179:3;-1:-1:-1;20260:47:13;;-1:-1:-1;14939:119:13;20260:47;19231:1082;;;;;;;;;;:::o;20318:184::-;20388:6;20441:2;20429:9;20420:7;20416:23;20412:32;20409:52;;;20457:1;20454;20447:12;20409:52;-1:-1:-1;20480:16:13;;20318:184;-1:-1:-1;20318:184:13:o;20507:135::-;20546:3;20567:17;;;20564:43;;20587:18;;:::i;:::-;-1:-1:-1;20634:1:13;20623:13;;20507:135::o

Swarm Source

ipfs://612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.