APE Price: $0.64 (+0.81%)

Token

Bored Ape Yacht Club Shadow (BAYC)

Overview

Max Total Supply

0 BAYC

Holders

5,388

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
6 BAYC
0xa26603eebef077439f5c909e00e3cb6e879aa83c
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
BoredApeYachtClubShadow

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

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

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

/**
 * @title BoredApeYachtClubShadow
 */
contract BoredApeYachtClubShadow is NFTShadow {
    constructor(address _beacon) NFTShadow(_beacon) {
        initialize(
            0x58A766B3210ceE94Ca150f767D842Eb87A8d7aE8,
            "Bored Ape Yacht Club Shadow",
            "BAYC",
            "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/",
            address(0),
            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 virtual 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 virtual 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
        virtual
        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 virtual {
        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 virtual {
        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 virtual {
        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 virtual 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 virtual override returns (string memory) {
        return _name;
    }

    /**
     * @notice Returns the symbol of the collection.
     * @return _symbol the symbol of the collection.
     */
    function symbol() public view virtual 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/",
    "sol-json/=lib/sol-json/src/",
    "ds-test/=lib/sol-json/lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/sol-json/lib/solady/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_beacon","type":"address"}],"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"}]

60a0604052346105c3576134306020813803918261001c816105c7565b9384928339810103126105c357516001600160a01b03811681036105c35760805261004760406105c7565b601b81527f426f7265642041706520596163687420436c756220536861646f770000000000602082015261007b60406105c7565b9060048252634241594360e01b602083015261009760606105c7565b60368082527f697066733a2f2f516d65536a53696e4870506e6d586d73704d6a776958794e3660208301527f7a533445397a63636172694752336a7863615774712f000000000000000000006040830152909290600254600181811c911680156105b9575b60208210146103dd57601f8111610556575b506020601f82116001146104f357819293945f926104e8575b50508160011b915f199060031b1c1916176002555b81516001600160401b0381116103fb57600354600181811c911680156104de575b60208210146103dd57601f811161047b575b50602092601f821160011461041a57928192935f9261040f575b50508160011b915f199060031b1c1916176003555b80516001600160401b0381116103fb57600454600181811c911680156103f1575b60208210146103dd57601f811161037a575b50602091601f821160011461031a579181925f9261030f575b50508160011b915f199060031b1c1916176004555b600580546001600160a01b0319169055638b78c6d81954610302577358a766b3210cee94ca150f767d842eb87a8d7ae8638b78c6d819557358a766b3210cee94ca150f767d842eb87a8d7ae85f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a35f80546001600160a01b03191690557f58a766b3210cee94ca150f767d842eb87a8d7ae800000000000000000000000068aa4ec00224afccfdb755604051612e4390816105ed823960805181818161036f015281816107ff01528181610a7d01528181611ab00152818161201b015281816123f70152818161294701528181612a3701528181612af60152612b9c0152f35b630dc149f05f526004601cfd5b015190505f806101ea565b601f1982169260045f52805f20915f5b8581106103625750836001951061034a575b505050811b016004556101ff565b01515f1960f88460031b161c191690555f808061033c565b9192602060018192868501518155019401920161032a565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106103d3575b601f0160051c01905b8181106103c857506101d1565b5f81556001016103bb565b90915081906103b2565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101bf565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610189565b601f1982169360035f52805f20915f5b868110610463575083600195961061044b575b505050811b0160035561019e565b01515f1960f88460031b161c191690555f808061043d565b9192602060018192868501518155019401920161042a565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106104d4575b601f0160051c01905b8181106104c9575061016f565b5f81556001016104bc565b90915081906104b3565b90607f169061015d565b015190505f80610127565b601f1982169060025f52805f20915f5b81811061053e57509583600195969710610526575b505050811b0160025561013c565b01515f1960f88460031b161c191690555f8080610518565b9192602060018192868b015181550194019201610503565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106105af575b601f0160051c01905b8181106105a4575061010e565b5f8155600101610597565b909150819061058e565b90607f16906100fc565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176103fb5760405256fe60806040526004361015610021575b3461001d5761001b612913565b005b5f80fd5b5f3560e01c806301ddc8bf1461034b57806301ffc9a71461034657806302fa7c471461034157806306fdde031461033c578063081812fc14610337578063095ea7b314610332578063098144d4146102f65780630a2121001461032d5780630c756a78146103285780630d705df614610323578063156c2c321461031e578063183a4f6e146103195780631c10893f146103145780631cd64df41461030f5780631de26e8e1461030a57806321f365091461030557806323b872dd1461030057806325692962146102fb57806329e38d5e146102f65780632a55205a146102f15780632de94807146102ec57806342842e0e146102e757806342966c68146102e25780634a4ee7b1146102dd578063514e62fc146102d8578063529470e8146102d357806354d1f13d146102ce57806358456fb5146102c95780636352211e146102c457806370319970146102bf57806370a08231146102ba578063715018a6146102b55780637347ebb9146102b05780638528e8d3146102ab5780638da5cb5b146102a657806395d89b41146102a157806399a2557a1461029c578063a22cb46514610297578063a9fc664e14610292578063b1dae6181461028d578063b45a3c0e14610288578063b88d4fde14610283578063c87b56dd1461027e578063e0df5b6f14610279578063e985e9c514610274578063ed0616781461026f578063f04e283e1461026a578063f2fde38b14610265578063f7dec9b414610260578063fd4fe8a81461025b5763fee81cf40361000e576118c4565b611829565b61179d565b61175e565b61170d565b6116ef565b6116a3565b611558565b611539565b6114c8565b61147d565b611467565b6113d9565b611363565b6112f3565b61124e565b611222565b611182565b6110b4565b611067565b611040565b611018565b610fe8565b610fc9565b610f85565b610f65565b610f21565b610ef5565b610e10565b610dd7565b610d9a565b610d0d565b610701565b610cc4565b610cb2565b610c5a565b610c09565b610bc4565b610b5e565b610b46565b610a11565b6109ea565b6109ce565b610781565b610655565b6105f7565b610521565b610495565b61039e565b61035a565b5f91031261001d57565b3461001d575f36600319011261001d576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461001d57602036600319011261001d576004356001600160e01b031981169081810361001d576103fd91635a2d1e0760e11b811491821561042e575b8215610412575b508115610401575b5060405190151581529081906020820190565b0390f35b632483248360e11b1490505f6103ea565b90915060e01c6301ffc9a7632a55205a8214911417905f6103e2565b80925060e01c635b5e139f8114906301ffc9a76380ac58cd821491141717916103db565b6001600160a01b0381160361001d57565b6084359061047082610452565b565b60a4359061047082610452565b60c435906001600160601b038216820361001d57565b3461001d57604036600319011261001d576004356104b281610452565b6024356001600160601b038116810361001d57638b78c6d8600c52335f52600160581b6020600c205416156104ea5761001b9161226d565b6382b429005f526004601cfd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b3461001d575f36600319011261001d576040515f600354610541816118fa565b80845290600181169081156105d35750600114610575575b6103fd83610569818503826110ed565b604051918291826104f7565b60035f9081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b8082106105b957509091508101602001610569610559565b9192600181602092548385880101520191019092916105a1565b60ff191660208086019190915291151560051b840190910191506105699050610559565b3461001d57602036600319011261001d576004355f818152673ec412a9852d173d60c11b601c5260209020810101805460601b1561064857600101546040516001600160a01b039091168152602090f35b63ceea21b65f526004601cfd5b604036600319011261001d5760043561066d81610452565b6024355f818152673ec412a9852d173d60c11b3317601c526020902081018101805491926001600160a01b039081169216908115610648578290823314331517156106dd575b600101557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b9050815f526030600c2054156106f45782906106b3565b634b6e7f185f526004601cfd5b3461001d575f36600319011261001d575f546040516001600160a01b039091168152602090f35b6004359063ffffffff8216820361001d57565b9181601f8401121561001d578235916001600160401b03831161001d576020808501948460051b01011161001d57565b608435906001600160801b038216820361001d57565b60a036600319011261001d57610795610728565b6024356001600160401b03811161001d576107b490369060040161073b565b91906044356107c281610452565b606435926107cf84610452565b6107d761076b565b905f5b8681106108c0575060405163f174883560e01b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016939092602084602481885afa93841561088a575f9461088f575b50843b1561001d575f9661086492604051998a988997889763c9df816760e01b895260048901611a54565b039134905af1801561088a5761087657005b806108845f61001b936110ed565b80610350565b611a25565b6108b291945060203d6020116108b9575b6108aa81836110ed565b810190611a10565b925f610839565b503d6108a0565b6108dc6108d86108d1838a896119fb565b35336122b2565b1590565b6109bf576108f46108ee8289886119fb565b35612310565b6109b05760019061090e6108d860055460ff9060a01c1690565b610997575b61094e610921828a896119fb565b355f818152673ec412a9852d173d60c11b601c526020902081010180546001600160a01b03198116189055565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a161161098e61097d838b8a6119fb565b604051903581529081906020820190565b0390a1016107da565b6109ab6109a5828a896119fb565b356125ca565b610913565b635a8181f760e01b5f5260045ffd5b63096dcfe360e31b5f5260045ffd5b3461001d575f36600319011261001d5760206040516120008152f35b3461001d575f36600319011261001d576040805163657711f560e11b815260016020820152f35b604036600319011261001d576004356001600160401b03811161001d57610a3c90369060040161073b565b906024356001600160401b03811161001d57610a5c90369060040161073b565b60405163f174883560e01b8152306004820152909390926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190602085602481865afa801561088a575f610add916020978291610b29575b5060405163fe084c8f60e01b815298899788968796339460048901612341565b039134905af1801561088a576020915f91610afc575b50604051908152f35b610b1c9150823d8411610b22575b610b1481836110ed565b810190612332565b5f610af3565b503d610b0a565b610b409150883d8a116108b9576108aa81836110ed565b5f610abd565b602036600319011261001d5761001b600435336129c5565b604036600319011261001d57600435610b7681610452565b60243590610b82612487565b638b78c6d8600c525f526020600c2090815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461001d57604036600319011261001d576020610bff600435610be681610452565b602435918291638b78c6d8600c525f526020600c205490565b1614604051908152f35b3461001d575f36600319011261001d57638b78c6d8600c52335f526120006020600c205416156104ea576005805460ff60a01b1916600160a01b179055005b602090600319011261001d5760043590565b3461001d57610c6836610c48565b5f526001602052602060018060a01b0360405f205416604051908152f35b606090600319011261001d57600435610c9e81610452565b90602435610cab81610452565b9060443590565b61001b610cbe36610c86565b91611aab565b5f36600319011261001d5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461001d57604036600319011261001d57600435602435905f5268aa4ec00224afccfdb760205260405f2054908160601c918215610d82575b6103fd908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b5068aa4ec00224afccfdb754606081901c9250610d46565b3461001d57602036600319011261001d576020610dcf600435610dbc81610452565b638b78c6d8600c525f526020600c205490565b604051908152f35b610de036610c86565b610ded8183859495611aab565b823b610df557005b61001b9260405192610e086020856110ed565b5f8452612538565b3461001d57602036600319011261001d576004355f818152673ec412a9852d173d60c11b601c5260209020810181015460a01c610e505761001b906125ca565b610e6281610e5d81611c1a565b612a35565b5f818152673ec412a9852d173d60c11b3317601c5260209020810181018054906001600160a01b03821690811561064857815f52806001019283548033148433141733151715610ee3575b905f948492610eda575b50189055601c600c20821981540190555f516020612dee5f395f51905f528280a4005b8590555f610eb7565b906030600c2054156106f45790610ead565b604036600319011261001d5761001b600435610f1081610452565b60243590610f1c612487565b6129c5565b3461001d57604036600319011261001d576020600435610f4081610452565b610f5a60243591638b78c6d8600c525f526020600c205490565b161515604051908152f35b3461001d575f36600319011261001d576020604051650400000000008152f35b5f36600319011261001d5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461001d575f36600319011261001d57604051600160581b8152602090f35b3461001d57602036600319011261001d576020611006600435611c1a565b6040516001600160a01b039091168152f35b3461001d575f36600319011261001d576005546040516001600160a01b039091168152602090f35b3461001d57602036600319011261001d576020610dcf60043561106281610452565b611c47565b5f36600319011261001d5761107a612487565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3600160ff1b638b78c6d81955005b3461001d575f36600319011261001d57602060ff60055460a01c166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761110e57604052565b6110d9565b6001600160401b03811161110e57601f01601f191660200190565b92919261113a82611113565b9161114860405193846110ed565b82948184528183011161001d578281602093845f960137010152565b9080601f8301121561001d5781602061117f9335910161112e565b90565b3461001d5760e036600319011261001d5760043561119f81610452565b6024356001600160401b03811161001d576111be903690600401611164565b906044356001600160401b03811161001d576111de903690600401611164565b91606435926001600160401b03841161001d5761120261001b943690600401611164565b61120a610463565b91611213610472565b9361121c61047f565b95611ec7565b3461001d575f36600319011261001d57638b78c6d819546040516001600160a01b039091168152602090f35b3461001d575f36600319011261001d576040515f60045461126e816118fa565b80845290600181169081156105d35750600114611295576103fd83610569818503826110ed565b60045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106112d957509091508101602001610569610559565b9192600181602092548385880101520191019092916112c1565b3461001d57606036600319011261001d5761131f60043561131381610452565b60243560443591612780565b6040518091602082016020835281518091526020604084019201905f5b81811061134a575050500390f35b825184528594506020938401939092019160010161133c565b3461001d57604036600319011261001d5760043561138081610452565b60243580151580910361001d5781601c52670a5a2e7a00000000600852335f52806030600c20555f5260018060a01b0316337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa3005b3461001d57602036600319011261001d576004356113f681610452565b638b78c6d8600c52335f52600160451b6020600c205416156104ea575f80546001600160a01b039283166001600160a01b0319821681179092556040805193909116835260208301919091527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91a1005b3461001d5761001b61147836610c48565b612019565b3461001d57602036600319011261001d5760206001600160601b036114be600435805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b1615604051908152f35b608036600319011261001d576004356114e081610452565b6024356114ec81610452565b606435916044356001600160401b03841161001d573660238501121561001d578360040135926001600160401b03841161001d57366024858701011161001d57602461001b9501926120e2565b3461001d57602036600319011261001d576103fd61056960043561217e565b3461001d57602036600319011261001d576004356001600160401b03811161001d57611588903690600401611164565b61159061224d565b80516001600160401b03811161110e576115b4816115af6002546118fa565b611c7a565b602091601f8211600114611625576115e2925f918361161a575b50508160011b915f199060031b1c19161790565b6002555b604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9190a1005b015190505f806115ce565b60025f52601f198216927f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f5b85811061168b57508360019510611673575b505050811b016002556115e6565b01515f1960f88460031b161c191690555f8080611665565b91926020600181928685015181550194019201611653565b3461001d57604036600319011261001d576004356116c081610452565b6024356116cc81610452565b601c52670a5a2e7a000000006008525f5260206030600c20546040519015158152f35b3461001d575f36600319011261001d576020604051600160451b8152f35b602036600319011261001d5760043561172581610452565b61172d612487565b63389a75e1600c52805f526020600c209081544211611751575f61001b9255612663565b636f5e88185f526004601cfd5b602036600319011261001d5760043561177681610452565b61177e612487565b8060601b156117905761001b90612663565b637448fbae5f526004601cfd5b606036600319011261001d576004356001600160401b03811161001d576117c890369060040161073b565b906024356001600160401b03811161001d576117e890369060040161073b565b604435916001600160801b038316830361001d57602094611808946123d7565b5f818152600183526040902080546001600160a01b03191633179055610dcf565b3461001d57602036600319011261001d577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604060043561186981610452565b61187161224d565b600580546001600160a01b0319166001600160a01b039290921691821790558151907faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a035f80a25f81525f196020820152a1005b3461001d57602036600319011261001d576004356118e181610452565b63389a75e1600c525f52602080600c2054604051908152f35b90600182811c92168015611928575b602083101461191457565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611909565b604051905f8260025491611945836118fa565b80835292600181169081156119c85750600114611969575b610470925003836110ed565b5060025f90815290917f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8183106119ac5750509060206104709282010161195d565b6020919350806001915483858901015201910190918492611994565b6020925061047094915060ff191682840152151560051b82010161195d565b634e487b7160e01b5f52603260045260245ffd5b9190811015611a0b5760051b0190565b6119e7565b9081602091031261001d575161117f81610452565b6040513d5f823e3d90fd5b81835290916001600160fb1b03831161001d5760209260051b809284830137010190565b9591926001600160801b039460a09699989463ffffffff611a8f94168952600180891b0316602089015260c0604089015260c0880191611a30565b5f196001861b0197881660608701529616608085015216910152565b9190337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603611b295760016001600160601b03611b0b84805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b1614611b1a5761047092612496565b6305b166a360e41b5f5260045ffd5b9091611b36838383612b98565b5f838152673ec412a9852d173d60c11b3317601c52602090208301830180546001600160a01b0393841693928316928116808414810215611c055750825f528160010180548033148533141715611bee575b611be5575b50838318189055601c600c205f198154019055815f52601c600c2060018154019063ffffffff8216840215611bd057555f516020612dee5f395f51905f525f80a4565b67ea553b3401336cea841560021b526004601cfd5b5f90555f611b8d565b6030600c2054611b8857634b6e7f185f526004601cfd5b67ceea21b6a1148100901560021b526004601cfd5b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690811561064857565b8015611c6d57673ec412a9852d173d60c11b601c525f5263ffffffff601c600c20541690565b638f4eb6045f526004601cfd5b601f8111611c86575050565b60025f5260205f20906020601f840160051c83019310611cc0575b601f0160051c01905b818110611cb5575050565b5f8155600101611caa565b9091508190611ca1565b601f8211611cd757505050565b5f5260205f20906020601f840160051c83019310611d0f575b601f0160051c01905b818110611d04575050565b5f8155600101611cf9565b9091508190611cf0565b9081516001600160401b03811161110e57611d4081611d396003546118fa565b6003611cca565b602092601f8211600114611d7457611d6f929382915f9261161a5750508160011b915f199060031b1c19161790565b600355565b60035f52601f198216937fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b915f5b868110611dd85750836001959610611dc0575b505050811b01600355565b01515f1960f88460031b161c191690555f8080611db5565b91926020600181928685015181550194019201611da2565b9081516001600160401b03811161110e57611e1781611e106004546118fa565b6004611cca565b602092601f8211600114611e4b57611e46929382915f9261161a5750508160011b915f199060031b1c19161790565b600455565b60045f52601f198216937f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b915f5b868110611eaf5750836001959610611e97575b505050811b01600455565b01515f1960f88460031b161c191690555f8080611e8c565b91926020600181928685015181550194019201611e79565b939190969594929687516001600160401b03811161110e57611eee816115af6002546118fa565b6020601f8211600114611f835792611f38611f7e969593611f3084611f3d95611f5a986104709e9f5f9261161a5750508160011b915f199060031b1c19161790565b600255611d19565b611df0565b60018060a01b03166001600160601b0360a01b6005541617600555565b611f63836126a6565b60018060a01b03166001600160601b0360a01b5f5416175f55565b61226d565b60025f52601f198216997f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9a5f5b8181106120015750936001846104709c9d611f5a9895611f3895611f3d98611f7e9d9c9a10611fe9575b505050811b01600255611d19565b01515f1960f88460031b161c191690555f8080611fdb565b838301518d556001909c019b60209384019301611fb1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036120d3575f818152600160205260409020546001600160a01b031680156120cf5761208b61207b835f52600160205260405f2090565b80546001600160a01b0319169055565b803b1561001d5760405163163b5cc360e31b815260048101929092525f908290602490829084905af1801561088a576120c15750565b806108845f610470936110ed565b5050565b63db70dad160e01b5f5260045ffd5b92936120ef838386611aab565b813b6120fd575b5050505050565b6121129461210c91369161112e565b92612538565b5f808080806120f6565b60208183031261001d578051906001600160401b03821161001d570181601f8201121561001d5780519061214f82611113565b9261215d60405194856110ed565b8284526020838301011161001d57815f9260208093018386015e8301015290565b5f818152673ec412a9852d173d60c11b601c5260209020810181015460601b1561223e576005546001600160a01b0316806121cd57506121c061117f9161283b565b6121c8611932565b612880565b61220d915f916121ed906001600160a01b03165b6001600160a01b031690565b604051808095819463c87b56dd60e01b8352600483019190602083019252565b03915afa90811561088a575f91612222575090565b61117f91503d805f833e61223681836110ed565b81019061211c565b63677510db60e11b5f5260045ffd5b638b78c6d8600c52335f52650400000000006020600c205416156104ea57565b906001600160601b03169061271082116122a55760601b8015612298571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b5f8281526001600160a01b03918216673ec412a9852d173d60c11b8117601c526020909120830190920180546001949392168015610648578083036122f657505050565b5f526030600c205415612307575050565b60010154149150565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b9081602091031261001d575190565b949291602092612369929998979960018060a01b0316875260a08488015260a0870191611a30565b84810360408601528281520191905f905b8082106123aa575050506001600160a01b0390941660608201526104709190608001906001600160801b03169052565b90919283359063ffffffff8216820361001d576020809163ffffffff60019416815201940192019061237a565b60405163f174883560e01b81523060048201529394936001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016929190602081602481875afa95861561088a57602096612457925f91610b29575060405163fe084c8f60e01b815298899788968796339460048901612341565b039134905af190811561088a575f9161246e575090565b61117f915060203d602011610b2257610b1481836110ed565b638b78c6d8195433036104ea57565b6124a1838383612b98565b5f838152673ec412a9852d173d60c11b601c52602090208301830180546001600160a01b0393841693928316928116808414810215611c055750825f52816001018054801585151760011715611bee57611be55750838318189055601c600c205f198154019055815f52601c600c2060018154019063ffffffff8216840215611bd057555f516020612dee5f395f51905f525f80a4565b9060a46020939460405195869463150b7a028652338787015260018060a01b03166040860152606085015260808085015280518091818060a08801526125b6575b505001905f601c8401915af1156125a8575b5163757a42ff60e11b0161259b57565b63d1a57ed65f526004601cfd5b3d1561258b573d5f823e3d90fd5b818760c08801920160045afa50805f612579565b6125d781610e5d81611c1a565b5f818152673ec412a9852d173d60c11b601c5260209020810181018054906001600160a01b03821690811561064857815f5280600101928354801560011715612651575b905f948492612648575b50189055601c600c20821981540190555f516020612dee5f395f51905f528280a4565b8590555f612625565b906030600c2054156106f4579061261b565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3801560ff1b17638b78c6d81955565b638b78c6d819546126ef576001600160a01b0316801560ff1b8117638b78c6d819555f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3565b630dc149f05f526004601cfd5b6001600160401b03811161110e5760051b60200190565b9061271d826126fc565b61272a60405191826110ed565b828152809261273b601f19916126fc565b0190602036910137565b634e487b7160e01b5f52601160045260245ffd5b5f1981146127675760010190565b612745565b8051821015611a0b5760209160051b010190565b90929161278c82611c47565b5f9261279782612713565b955b838111156127de57505050506127ae81612713565b905f5b8181106127bf575090925050565b806127cc6001928761276c565b516127d7828661276c565b52016127b1565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0383811691161461281b575b61281690612759565b612799565b93808561282a6001938a61276c565b52019382850361280d575050505050565b90604051600a608082019360a083016040525f8552935b5f19019360308282060185530492831561286e57600a90612852565b809350608091030191601f1901918252565b6040518151909392909160208301601f19165b8181015186820152601f19019081156128ac5790612893565b505080519084830160208301601f19165b8281015182820152601f19019182156128d657916128bd565b50505060409101808401905f6020830152845201604052565b908160051b918083046020149015171561276757565b606401908160641161276757565b5f3560e01c6340c10f19810361293b57506104706024356004356001600160a01b0316612d60565b6392772833036129b6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036120d3576044356024356001600160a01b03165f5b82811061299257505050565b806129b0836129aa6129a56001956128ef565b612905565b35612c73565b01612986565b631e085ca760e11b5f5260045ffd5b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612a69575050565b612a7282612310565b8015612ae3575b6120d3575f546001600160a01b031680612a9257505050565b612aa4906001600160a01b03166121e1565b91823b1561001d5760405163657711f560e11b8152925f92849283918291612ad29187903360048601612a0a565b03915afa801561088a576120c15750565b506001600160a01b03811615612a79565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612b28575050565b612b3182612310565b8015612b90575b6120d3575f546001600160a01b031680612b5157505050565b612b63906001600160a01b03166121e1565b91823b1561001d5760405163657711f560e11b8152925f92849283918291612ad291873360048601612a0a565b506001612b38565b90917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612bcf57505050565b612bd881612310565b8015612c62575b6120d3575f546001600160a01b031680612bfa575b50505050565b612c0c906001600160a01b03166121e1565b803b1561001d57612c37935f936040519586948593849363657711f560e11b85523360048601612a0a565b03915afa801561088a57612c4e575b808080612bf4565b806108845f612c5c936110ed565b5f612c46565b506001600160a01b03821615612bdf565b906001600160601b03612ca083805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b16611b1a575f828152673ec412a9852d173d60c11b601c5260209081902083018301547ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429391926001600160a01b039091169082908280612d375750612d069250612d60565b805f52673ec412a9852d173d60c11b601c52815f208101810180548060a01c60011860a01b189055604051908152a1565b6001600160a01b03821603612d4f575b505050612d06565b612d5892612496565b5f8181612d47565b612d6a8282612af4565b60018060a01b0316815f52673ec412a9852d173d60c11b601c5260205f208201820180548060601b612de05782179055805f52601c600c2060018154019063ffffffff8216830215612dcb57555f5f516020612dee5f395f51905f528180a4565b67ea553b3401336cea831560021b526004601cfd5b63c991cbb15f526004601cfdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202905636dba5b9eeab3dd04124fe5d831f35328386f49e321bcba5a3e3619b83164736f6c634300081c003300000000000000000000000000000000000087c6dbadc090d39bc10316f20658

Deployed Bytecode

0x60806040526004361015610021575b3461001d5761001b612913565b005b5f80fd5b5f3560e01c806301ddc8bf1461034b57806301ffc9a71461034657806302fa7c471461034157806306fdde031461033c578063081812fc14610337578063095ea7b314610332578063098144d4146102f65780630a2121001461032d5780630c756a78146103285780630d705df614610323578063156c2c321461031e578063183a4f6e146103195780631c10893f146103145780631cd64df41461030f5780631de26e8e1461030a57806321f365091461030557806323b872dd1461030057806325692962146102fb57806329e38d5e146102f65780632a55205a146102f15780632de94807146102ec57806342842e0e146102e757806342966c68146102e25780634a4ee7b1146102dd578063514e62fc146102d8578063529470e8146102d357806354d1f13d146102ce57806358456fb5146102c95780636352211e146102c457806370319970146102bf57806370a08231146102ba578063715018a6146102b55780637347ebb9146102b05780638528e8d3146102ab5780638da5cb5b146102a657806395d89b41146102a157806399a2557a1461029c578063a22cb46514610297578063a9fc664e14610292578063b1dae6181461028d578063b45a3c0e14610288578063b88d4fde14610283578063c87b56dd1461027e578063e0df5b6f14610279578063e985e9c514610274578063ed0616781461026f578063f04e283e1461026a578063f2fde38b14610265578063f7dec9b414610260578063fd4fe8a81461025b5763fee81cf40361000e576118c4565b611829565b61179d565b61175e565b61170d565b6116ef565b6116a3565b611558565b611539565b6114c8565b61147d565b611467565b6113d9565b611363565b6112f3565b61124e565b611222565b611182565b6110b4565b611067565b611040565b611018565b610fe8565b610fc9565b610f85565b610f65565b610f21565b610ef5565b610e10565b610dd7565b610d9a565b610d0d565b610701565b610cc4565b610cb2565b610c5a565b610c09565b610bc4565b610b5e565b610b46565b610a11565b6109ea565b6109ce565b610781565b610655565b6105f7565b610521565b610495565b61039e565b61035a565b5f91031261001d57565b3461001d575f36600319011261001d576040517f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b03168152602090f35b3461001d57602036600319011261001d576004356001600160e01b031981169081810361001d576103fd91635a2d1e0760e11b811491821561042e575b8215610412575b508115610401575b5060405190151581529081906020820190565b0390f35b632483248360e11b1490505f6103ea565b90915060e01c6301ffc9a7632a55205a8214911417905f6103e2565b80925060e01c635b5e139f8114906301ffc9a76380ac58cd821491141717916103db565b6001600160a01b0381160361001d57565b6084359061047082610452565b565b60a4359061047082610452565b60c435906001600160601b038216820361001d57565b3461001d57604036600319011261001d576004356104b281610452565b6024356001600160601b038116810361001d57638b78c6d8600c52335f52600160581b6020600c205416156104ea5761001b9161226d565b6382b429005f526004601cfd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b3461001d575f36600319011261001d576040515f600354610541816118fa565b80845290600181169081156105d35750600114610575575b6103fd83610569818503826110ed565b604051918291826104f7565b60035f9081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b8082106105b957509091508101602001610569610559565b9192600181602092548385880101520191019092916105a1565b60ff191660208086019190915291151560051b840190910191506105699050610559565b3461001d57602036600319011261001d576004355f818152673ec412a9852d173d60c11b601c5260209020810101805460601b1561064857600101546040516001600160a01b039091168152602090f35b63ceea21b65f526004601cfd5b604036600319011261001d5760043561066d81610452565b6024355f818152673ec412a9852d173d60c11b3317601c526020902081018101805491926001600160a01b039081169216908115610648578290823314331517156106dd575b600101557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b9050815f526030600c2054156106f45782906106b3565b634b6e7f185f526004601cfd5b3461001d575f36600319011261001d575f546040516001600160a01b039091168152602090f35b6004359063ffffffff8216820361001d57565b9181601f8401121561001d578235916001600160401b03831161001d576020808501948460051b01011161001d57565b608435906001600160801b038216820361001d57565b60a036600319011261001d57610795610728565b6024356001600160401b03811161001d576107b490369060040161073b565b91906044356107c281610452565b606435926107cf84610452565b6107d761076b565b905f5b8681106108c0575060405163f174883560e01b81523060048201526001600160a01b037f00000000000000000000000000000000000087c6dbadc090d39bc10316f2065816939092602084602481885afa93841561088a575f9461088f575b50843b1561001d575f9661086492604051998a988997889763c9df816760e01b895260048901611a54565b039134905af1801561088a5761087657005b806108845f61001b936110ed565b80610350565b611a25565b6108b291945060203d6020116108b9575b6108aa81836110ed565b810190611a10565b925f610839565b503d6108a0565b6108dc6108d86108d1838a896119fb565b35336122b2565b1590565b6109bf576108f46108ee8289886119fb565b35612310565b6109b05760019061090e6108d860055460ff9060a01c1690565b610997575b61094e610921828a896119fb565b355f818152673ec412a9852d173d60c11b601c526020902081010180546001600160a01b03198116189055565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a161161098e61097d838b8a6119fb565b604051903581529081906020820190565b0390a1016107da565b6109ab6109a5828a896119fb565b356125ca565b610913565b635a8181f760e01b5f5260045ffd5b63096dcfe360e31b5f5260045ffd5b3461001d575f36600319011261001d5760206040516120008152f35b3461001d575f36600319011261001d576040805163657711f560e11b815260016020820152f35b604036600319011261001d576004356001600160401b03811161001d57610a3c90369060040161073b565b906024356001600160401b03811161001d57610a5c90369060040161073b565b60405163f174883560e01b8152306004820152909390926001600160a01b037f00000000000000000000000000000000000087c6dbadc090d39bc10316f20658169190602085602481865afa801561088a575f610add916020978291610b29575b5060405163fe084c8f60e01b815298899788968796339460048901612341565b039134905af1801561088a576020915f91610afc575b50604051908152f35b610b1c9150823d8411610b22575b610b1481836110ed565b810190612332565b5f610af3565b503d610b0a565b610b409150883d8a116108b9576108aa81836110ed565b5f610abd565b602036600319011261001d5761001b600435336129c5565b604036600319011261001d57600435610b7681610452565b60243590610b82612487565b638b78c6d8600c525f526020600c2090815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461001d57604036600319011261001d576020610bff600435610be681610452565b602435918291638b78c6d8600c525f526020600c205490565b1614604051908152f35b3461001d575f36600319011261001d57638b78c6d8600c52335f526120006020600c205416156104ea576005805460ff60a01b1916600160a01b179055005b602090600319011261001d5760043590565b3461001d57610c6836610c48565b5f526001602052602060018060a01b0360405f205416604051908152f35b606090600319011261001d57600435610c9e81610452565b90602435610cab81610452565b9060443590565b61001b610cbe36610c86565b91611aab565b5f36600319011261001d5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461001d57604036600319011261001d57600435602435905f5268aa4ec00224afccfdb760205260405f2054908160601c918215610d82575b6103fd908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b5068aa4ec00224afccfdb754606081901c9250610d46565b3461001d57602036600319011261001d576020610dcf600435610dbc81610452565b638b78c6d8600c525f526020600c205490565b604051908152f35b610de036610c86565b610ded8183859495611aab565b823b610df557005b61001b9260405192610e086020856110ed565b5f8452612538565b3461001d57602036600319011261001d576004355f818152673ec412a9852d173d60c11b601c5260209020810181015460a01c610e505761001b906125ca565b610e6281610e5d81611c1a565b612a35565b5f818152673ec412a9852d173d60c11b3317601c5260209020810181018054906001600160a01b03821690811561064857815f52806001019283548033148433141733151715610ee3575b905f948492610eda575b50189055601c600c20821981540190555f516020612dee5f395f51905f528280a4005b8590555f610eb7565b906030600c2054156106f45790610ead565b604036600319011261001d5761001b600435610f1081610452565b60243590610f1c612487565b6129c5565b3461001d57604036600319011261001d576020600435610f4081610452565b610f5a60243591638b78c6d8600c525f526020600c205490565b161515604051908152f35b3461001d575f36600319011261001d576020604051650400000000008152f35b5f36600319011261001d5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461001d575f36600319011261001d57604051600160581b8152602090f35b3461001d57602036600319011261001d576020611006600435611c1a565b6040516001600160a01b039091168152f35b3461001d575f36600319011261001d576005546040516001600160a01b039091168152602090f35b3461001d57602036600319011261001d576020610dcf60043561106281610452565b611c47565b5f36600319011261001d5761107a612487565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3600160ff1b638b78c6d81955005b3461001d575f36600319011261001d57602060ff60055460a01c166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761110e57604052565b6110d9565b6001600160401b03811161110e57601f01601f191660200190565b92919261113a82611113565b9161114860405193846110ed565b82948184528183011161001d578281602093845f960137010152565b9080601f8301121561001d5781602061117f9335910161112e565b90565b3461001d5760e036600319011261001d5760043561119f81610452565b6024356001600160401b03811161001d576111be903690600401611164565b906044356001600160401b03811161001d576111de903690600401611164565b91606435926001600160401b03841161001d5761120261001b943690600401611164565b61120a610463565b91611213610472565b9361121c61047f565b95611ec7565b3461001d575f36600319011261001d57638b78c6d819546040516001600160a01b039091168152602090f35b3461001d575f36600319011261001d576040515f60045461126e816118fa565b80845290600181169081156105d35750600114611295576103fd83610569818503826110ed565b60045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106112d957509091508101602001610569610559565b9192600181602092548385880101520191019092916112c1565b3461001d57606036600319011261001d5761131f60043561131381610452565b60243560443591612780565b6040518091602082016020835281518091526020604084019201905f5b81811061134a575050500390f35b825184528594506020938401939092019160010161133c565b3461001d57604036600319011261001d5760043561138081610452565b60243580151580910361001d5781601c52670a5a2e7a00000000600852335f52806030600c20555f5260018060a01b0316337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa3005b3461001d57602036600319011261001d576004356113f681610452565b638b78c6d8600c52335f52600160451b6020600c205416156104ea575f80546001600160a01b039283166001600160a01b0319821681179092556040805193909116835260208301919091527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91a1005b3461001d5761001b61147836610c48565b612019565b3461001d57602036600319011261001d5760206001600160601b036114be600435805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b1615604051908152f35b608036600319011261001d576004356114e081610452565b6024356114ec81610452565b606435916044356001600160401b03841161001d573660238501121561001d578360040135926001600160401b03841161001d57366024858701011161001d57602461001b9501926120e2565b3461001d57602036600319011261001d576103fd61056960043561217e565b3461001d57602036600319011261001d576004356001600160401b03811161001d57611588903690600401611164565b61159061224d565b80516001600160401b03811161110e576115b4816115af6002546118fa565b611c7a565b602091601f8211600114611625576115e2925f918361161a575b50508160011b915f199060031b1c19161790565b6002555b604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9190a1005b015190505f806115ce565b60025f52601f198216927f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f5b85811061168b57508360019510611673575b505050811b016002556115e6565b01515f1960f88460031b161c191690555f8080611665565b91926020600181928685015181550194019201611653565b3461001d57604036600319011261001d576004356116c081610452565b6024356116cc81610452565b601c52670a5a2e7a000000006008525f5260206030600c20546040519015158152f35b3461001d575f36600319011261001d576020604051600160451b8152f35b602036600319011261001d5760043561172581610452565b61172d612487565b63389a75e1600c52805f526020600c209081544211611751575f61001b9255612663565b636f5e88185f526004601cfd5b602036600319011261001d5760043561177681610452565b61177e612487565b8060601b156117905761001b90612663565b637448fbae5f526004601cfd5b606036600319011261001d576004356001600160401b03811161001d576117c890369060040161073b565b906024356001600160401b03811161001d576117e890369060040161073b565b604435916001600160801b038316830361001d57602094611808946123d7565b5f818152600183526040902080546001600160a01b03191633179055610dcf565b3461001d57602036600319011261001d577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604060043561186981610452565b61187161224d565b600580546001600160a01b0319166001600160a01b039290921691821790558151907faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a035f80a25f81525f196020820152a1005b3461001d57602036600319011261001d576004356118e181610452565b63389a75e1600c525f52602080600c2054604051908152f35b90600182811c92168015611928575b602083101461191457565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611909565b604051905f8260025491611945836118fa565b80835292600181169081156119c85750600114611969575b610470925003836110ed565b5060025f90815290917f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8183106119ac5750509060206104709282010161195d565b6020919350806001915483858901015201910190918492611994565b6020925061047094915060ff191682840152151560051b82010161195d565b634e487b7160e01b5f52603260045260245ffd5b9190811015611a0b5760051b0190565b6119e7565b9081602091031261001d575161117f81610452565b6040513d5f823e3d90fd5b81835290916001600160fb1b03831161001d5760209260051b809284830137010190565b9591926001600160801b039460a09699989463ffffffff611a8f94168952600180891b0316602089015260c0604089015260c0880191611a30565b5f196001861b0197881660608701529616608085015216910152565b9190337f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b031603611b295760016001600160601b03611b0b84805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b1614611b1a5761047092612496565b6305b166a360e41b5f5260045ffd5b9091611b36838383612b98565b5f838152673ec412a9852d173d60c11b3317601c52602090208301830180546001600160a01b0393841693928316928116808414810215611c055750825f528160010180548033148533141715611bee575b611be5575b50838318189055601c600c205f198154019055815f52601c600c2060018154019063ffffffff8216840215611bd057555f516020612dee5f395f51905f525f80a4565b67ea553b3401336cea841560021b526004601cfd5b5f90555f611b8d565b6030600c2054611b8857634b6e7f185f526004601cfd5b67ceea21b6a1148100901560021b526004601cfd5b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690811561064857565b8015611c6d57673ec412a9852d173d60c11b601c525f5263ffffffff601c600c20541690565b638f4eb6045f526004601cfd5b601f8111611c86575050565b60025f5260205f20906020601f840160051c83019310611cc0575b601f0160051c01905b818110611cb5575050565b5f8155600101611caa565b9091508190611ca1565b601f8211611cd757505050565b5f5260205f20906020601f840160051c83019310611d0f575b601f0160051c01905b818110611d04575050565b5f8155600101611cf9565b9091508190611cf0565b9081516001600160401b03811161110e57611d4081611d396003546118fa565b6003611cca565b602092601f8211600114611d7457611d6f929382915f9261161a5750508160011b915f199060031b1c19161790565b600355565b60035f52601f198216937fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b915f5b868110611dd85750836001959610611dc0575b505050811b01600355565b01515f1960f88460031b161c191690555f8080611db5565b91926020600181928685015181550194019201611da2565b9081516001600160401b03811161110e57611e1781611e106004546118fa565b6004611cca565b602092601f8211600114611e4b57611e46929382915f9261161a5750508160011b915f199060031b1c19161790565b600455565b60045f52601f198216937f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b915f5b868110611eaf5750836001959610611e97575b505050811b01600455565b01515f1960f88460031b161c191690555f8080611e8c565b91926020600181928685015181550194019201611e79565b939190969594929687516001600160401b03811161110e57611eee816115af6002546118fa565b6020601f8211600114611f835792611f38611f7e969593611f3084611f3d95611f5a986104709e9f5f9261161a5750508160011b915f199060031b1c19161790565b600255611d19565b611df0565b60018060a01b03166001600160601b0360a01b6005541617600555565b611f63836126a6565b60018060a01b03166001600160601b0360a01b5f5416175f55565b61226d565b60025f52601f198216997f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9a5f5b8181106120015750936001846104709c9d611f5a9895611f3895611f3d98611f7e9d9c9a10611fe9575b505050811b01600255611d19565b01515f1960f88460031b161c191690555f8080611fdb565b838301518d556001909c019b60209384019301611fb1565b7f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b031633036120d3575f818152600160205260409020546001600160a01b031680156120cf5761208b61207b835f52600160205260405f2090565b80546001600160a01b0319169055565b803b1561001d5760405163163b5cc360e31b815260048101929092525f908290602490829084905af1801561088a576120c15750565b806108845f610470936110ed565b5050565b63db70dad160e01b5f5260045ffd5b92936120ef838386611aab565b813b6120fd575b5050505050565b6121129461210c91369161112e565b92612538565b5f808080806120f6565b60208183031261001d578051906001600160401b03821161001d570181601f8201121561001d5780519061214f82611113565b9261215d60405194856110ed565b8284526020838301011161001d57815f9260208093018386015e8301015290565b5f818152673ec412a9852d173d60c11b601c5260209020810181015460601b1561223e576005546001600160a01b0316806121cd57506121c061117f9161283b565b6121c8611932565b612880565b61220d915f916121ed906001600160a01b03165b6001600160a01b031690565b604051808095819463c87b56dd60e01b8352600483019190602083019252565b03915afa90811561088a575f91612222575090565b61117f91503d805f833e61223681836110ed565b81019061211c565b63677510db60e11b5f5260045ffd5b638b78c6d8600c52335f52650400000000006020600c205416156104ea57565b906001600160601b03169061271082116122a55760601b8015612298571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b5f8281526001600160a01b03918216673ec412a9852d173d60c11b8117601c526020909120830190920180546001949392168015610648578083036122f657505050565b5f526030600c205415612307575050565b60010154149150565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b9081602091031261001d575190565b949291602092612369929998979960018060a01b0316875260a08488015260a0870191611a30565b84810360408601528281520191905f905b8082106123aa575050506001600160a01b0390941660608201526104709190608001906001600160801b03169052565b90919283359063ffffffff8216820361001d576020809163ffffffff60019416815201940192019061237a565b60405163f174883560e01b81523060048201529394936001600160a01b037f00000000000000000000000000000000000087c6dbadc090d39bc10316f2065816929190602081602481875afa95861561088a57602096612457925f91610b29575060405163fe084c8f60e01b815298899788968796339460048901612341565b039134905af190811561088a575f9161246e575090565b61117f915060203d602011610b2257610b1481836110ed565b638b78c6d8195433036104ea57565b6124a1838383612b98565b5f838152673ec412a9852d173d60c11b601c52602090208301830180546001600160a01b0393841693928316928116808414810215611c055750825f52816001018054801585151760011715611bee57611be55750838318189055601c600c205f198154019055815f52601c600c2060018154019063ffffffff8216840215611bd057555f516020612dee5f395f51905f525f80a4565b9060a46020939460405195869463150b7a028652338787015260018060a01b03166040860152606085015260808085015280518091818060a08801526125b6575b505001905f601c8401915af1156125a8575b5163757a42ff60e11b0161259b57565b63d1a57ed65f526004601cfd5b3d1561258b573d5f823e3d90fd5b818760c08801920160045afa50805f612579565b6125d781610e5d81611c1a565b5f818152673ec412a9852d173d60c11b601c5260209020810181018054906001600160a01b03821690811561064857815f5280600101928354801560011715612651575b905f948492612648575b50189055601c600c20821981540190555f516020612dee5f395f51905f528280a4565b8590555f612625565b906030600c2054156106f4579061261b565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3801560ff1b17638b78c6d81955565b638b78c6d819546126ef576001600160a01b0316801560ff1b8117638b78c6d819555f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3565b630dc149f05f526004601cfd5b6001600160401b03811161110e5760051b60200190565b9061271d826126fc565b61272a60405191826110ed565b828152809261273b601f19916126fc565b0190602036910137565b634e487b7160e01b5f52601160045260245ffd5b5f1981146127675760010190565b612745565b8051821015611a0b5760209160051b010190565b90929161278c82611c47565b5f9261279782612713565b955b838111156127de57505050506127ae81612713565b905f5b8181106127bf575090925050565b806127cc6001928761276c565b516127d7828661276c565b52016127b1565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0383811691161461281b575b61281690612759565b612799565b93808561282a6001938a61276c565b52019382850361280d575050505050565b90604051600a608082019360a083016040525f8552935b5f19019360308282060185530492831561286e57600a90612852565b809350608091030191601f1901918252565b6040518151909392909160208301601f19165b8181015186820152601f19019081156128ac5790612893565b505080519084830160208301601f19165b8281015182820152601f19019182156128d657916128bd565b50505060409101808401905f6020830152845201604052565b908160051b918083046020149015171561276757565b606401908160641161276757565b5f3560e01c6340c10f19810361293b57506104706024356004356001600160a01b0316612d60565b6392772833036129b6577f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b031633036120d3576044356024356001600160a01b03165f5b82811061299257505050565b806129b0836129aa6129a56001956128ef565b612905565b35612c73565b01612986565b631e085ca760e11b5f5260045ffd5b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b7f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b03163303612a69575050565b612a7282612310565b8015612ae3575b6120d3575f546001600160a01b031680612a9257505050565b612aa4906001600160a01b03166121e1565b91823b1561001d5760405163657711f560e11b8152925f92849283918291612ad29187903360048601612a0a565b03915afa801561088a576120c15750565b506001600160a01b03811615612a79565b7f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b03163303612b28575050565b612b3182612310565b8015612b90575b6120d3575f546001600160a01b031680612b5157505050565b612b63906001600160a01b03166121e1565b91823b1561001d5760405163657711f560e11b8152925f92849283918291612ad291873360048601612a0a565b506001612b38565b90917f00000000000000000000000000000000000087c6dbadc090d39bc10316f206586001600160a01b03163303612bcf57505050565b612bd881612310565b8015612c62575b6120d3575f546001600160a01b031680612bfa575b50505050565b612c0c906001600160a01b03166121e1565b803b1561001d57612c37935f936040519586948593849363657711f560e11b85523360048601612a0a565b03915afa801561088a57612c4e575b808080612bf4565b806108845f612c5c936110ed565b5f612c46565b506001600160a01b03821615612bdf565b906001600160601b03612ca083805f52673ec412a9852d173d60c11b601c5260205f208101015460a01c90565b16611b1a575f828152673ec412a9852d173d60c11b601c5260209081902083018301547ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429391926001600160a01b039091169082908280612d375750612d069250612d60565b805f52673ec412a9852d173d60c11b601c52815f208101810180548060a01c60011860a01b189055604051908152a1565b6001600160a01b03821603612d4f575b505050612d06565b612d5892612496565b5f8181612d47565b612d6a8282612af4565b60018060a01b0316815f52673ec412a9852d173d60c11b601c5260205f208201820180548060601b612de05782179055805f52601c600c2060018154019063ffffffff8216830215612dcb57555f5f516020612dee5f395f51905f528180a4565b67ea553b3401336cea831560021b526004601cfd5b63c991cbb15f526004601cfdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202905636dba5b9eeab3dd04124fe5d831f35328386f49e321bcba5a3e3619b83164736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000087c6dbadc090d39bc10316f20658

-----Decoded View---------------
Arg [0] : _beacon (address): 0x00000000000087c6dbaDC090d39BC10316f20658

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000087c6dbadc090d39bc10316f20658


Deployed Bytecode Sourcemap

144:391:6:-:0;;;;;;;;;-1:-1:-1;144:391:6;;;3901:54:5;;:::i;:::-;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;2463:48:5;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;;;;;144:391:6;;;;;;;;;;-1:-1:-1;;;12286:41:5;;;:82;;;;144:391:6;12286:136:5;;;;144:391:6;12286:173:5;;;;;144:391:6;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;12286:173:5;-1:-1:-1;;;12426:33:5;;-1:-1:-1;12286:173:5;;;:136;2894:182:2;;;;;;;;;;;;12286:136:5;;;;:82;15006:232:3;;;;;;;;;;;;;;;;;12286:82:5;;;144:391:6;-1:-1:-1;;;;;144:391:6;;;;;:::o;:::-;;;;;;;:::i;:::-;:::o;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;:::o;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;144:391:6;;;;;;4770:437:1;;;;-1:-1:-1;4770:437:1;144:391:6;17180:7:1;;4770:437;;;;;;;;10717:12:5;;;:::i;4770:437:1:-;;-1:-1:-1;4770:437:1;144:391:6;4770:437:1;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;:::o;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;;13239:5:5;144:391:6;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;13239:5:5;144:391:6;;;;;;;-1:-1:-1;144:391:6;;;;;;;-1:-1:-1;144:391:6;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;;;;;;;;;;;;-1:-1:-1;144:391:6;;-1:-1:-1;144:391:6;;;;;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;8230:395:3;;;-1:-1:-1;;;8230:395:3;;144:391:6;8230:395:3;;;;;;;;;;;;;;;144:391:6;;-1:-1:-1;;;;;144:391:6;;;;;;;;8230:395:3;;-1:-1:-1;8230:395:3;144:391:6;8230:395:3;;144:391:6;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;-1:-1:-1;29125:1350:3;;;-1:-1:-1;;;9013:10:3;29125:1350;;;144:391:6;29125:1350:3;;;;;;;;144:391:6;;-1:-1:-1;;;;;29125:1350:3;;;;;;;;;;9013:10;;;;29125:1350;9013:10;29125:1350;;;;;144:391:6;29125:1350:3;;;;-1:-1:-1;29125:1350:3;;144:391:6;29125:1350:3;;;;-1:-1:-1;29125:1350:3;;;;;;;;;;;;;;-1:-1:-1;29125:1350:3;144:391:6;29125:1350:3;;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;:::o;:::-;;;-1:-1:-1;;144:391:6;;;;;;:::i;:::-;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;:::i;:::-;8108:13:5;-1:-1:-1;8123:19:5;;;;;;-1:-1:-1;144:391:6;;-1:-1:-1;;;8531:60:5;;8585:4;144:391:6;8531:60:5;;144:391:6;-1:-1:-1;;;;;8539:23:5;144:391:6;;;;;;;;;8531:60:5;;;;;;;-1:-1:-1;8531:60:5;;;8103:386;8601:170;;;;;;-1:-1:-1;144:391:6;8601:170:5;144:391:6;;;;;;;;;;;;;8601:170:5;;144:391:6;8601:170:5;;;:::i;:::-;;8646:9;;8601:170;;;;;;;;;144:391:6;8601:170:5;;;-1:-1:-1;8601:170:5;;;:::i;:::-;;;:::i;:::-;;:::i;8531:60::-;;;;;144:391:6;8531:60:5;144:391:6;8531:60:5;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;8144:3;8167:44;8168:43;8199:11;;;;;:::i;:::-;144:391:6;8187:10:5;8168:43;:::i;:::-;8167:44;;144:391:6;8167:44:5;8163:78;;8259:20;8267:11;;;;;:::i;:::-;144:391:6;8259:20:5;:::i;:::-;8255:46;;144:391:6;;8320:18:5;144:391:6;8321:17:5;144:391:6;;;;;;;;8320:18:5;8316:75;;8144:3;8432:6;8419:11;;;;;:::i;:::-;144:391:6;;18808:307:3;;;-1:-1:-1;;;18808:307:3;;;;;;;;;;-1:-1:-1;;;;;;18808:307:3;;;;;18689:432;8432:6:5;8459:19;;8466:11;;;;;:::i;:::-;144:391:6;;;;;;;;;;;;;;8459:19:5;;;;144:391:6;8108:13:5;;8316:75;24033:2:3;8364:11:5;;;;;:::i;:::-;144:391:6;24033:2:3;:::i;:::-;8316:75:5;;8255:46;8288:13;;;-1:-1:-1;8288:13:5;144:391:6;-1:-1:-1;8288:13:5;8163:78;8220:21;;;-1:-1:-1;8220:21:5;144:391:6;-1:-1:-1;8220:21:5;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;;;;13430:7:1;144:391:6;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;-1:-1:-1;;;144:391:6;;14880:4:5;144:391:6;;;;;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;15083:60:5;;15137:4;144:391:6;15083:60:5;;144:391:6;6317:24:5;;144:391:6;;-1:-1:-1;;;;;15091:23:5;144:391:6;;6317:24:5;144:391:6;;;;;15083:60:5;;;;;;-1:-1:-1;15160:149:5;15083:60;144:391:6;15083:60:5;;;;;144:391:6;-1:-1:-1;144:391:6;;-1:-1:-1;;;15160:149:5;;144:391:6;;;;;;;15271:10:5;;144:391:6;15160:149:5;;;:::i;:::-;;15205:9;;15160:149;;;;;;;144:391:6;15160:149:5;-1:-1:-1;15160:149:5;;;144:391:6;15153:156:5;144:391:6;;;;;;15160:149:5;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;15083:60;;;;;;;;;;;;;;:::i;:::-;;;;144:391:6;;;-1:-1:-1;;144:391:6;;;;4572:5:1;144:391:6;;10375:10:1;4572:5;:::i;144:391:6:-;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;12478:70:0;;;:::i;:::-;3246:831:1;;;-1:-1:-1;3246:831:1;;;;;;;;;;;;;;;;-1:-1:-1;3246:831:1;;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;11444:13:1;144:391:6;;;;;:::i;:::-;;;11444:13:1;;;10859:219;;;;;;;;;10731:353;;11444:13;:21;:30;144:391:6;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;4770:437:1;;;;144:391:6;4770:437:1;13430:7;4770:437;;;;;;;;9076:24:5;144:391:6;;-1:-1:-1;;;;144:391:6;-1:-1:-1;;;144:391:6;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;-1:-1:-1;144:391:6;2976:64:5;144:391:6;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;:::i;:::-;;;:::i;:::-;;;-1:-1:-1;;144:391:6;;;;9239:383:0;;;;144:391:6;9239:383:0;7972:9;9132:15;144:391:6;9239:383:0;;;;;;144:391:6;9239:383:0;;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;-1:-1:-1;3447:784:2;;144:391:6;3447:784:2;144:391:6;-1:-1:-1;3447:784:2;;;;;;;;;;;144:391:6;;3447:784:2;;;;;;;;;;;;;;;;;2531:5;144:391:6;;3447:784:2;;;;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;3447:784:2;-1:-1:-1;3447:784:2;;;;;;;-1:-1:-1;3447:784:2;;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;;;:::i;:::-;10859:219:1;;;;;;;;;10731:353;;144:391:6;;;;;;;;;;;:::i;:::-;13825:2:3;;;;;;;:::i;:::-;38334:89;;13838:58;;144:391:6;13838:58:3;13856:40;144:391:6;;;;;;;;:::i;:::-;;;;13856:40:3;:::i;144:391:6:-;;;;;;-1:-1:-1;;144:391:6;;;;;;18300:179:3;;;;-1:-1:-1;;;18300:179:3;;;;;;;;;;;;11061:16:5;;24033:2:3;;;:::i;11057:118:5:-;24475:2:3;24414:11;;;;:::i;:::-;24475:2;:::i;:::-;-1:-1:-1;24531:1870:3;;;-1:-1:-1;;;11144:10:5;24531:1870:3;;;144:391:6;24531:1870:3;;;;;;;;;-1:-1:-1;;;;;24531:1870:3;;;;;;;;-1:-1:-1;24531:1870:3;;;;;;;11144:10:5;;24531:1870:3;11144:10:5;;24531:1870:3;;11144:10:5;24531:1870:3;;;;;11057:118:5;24531:1870:3;-1:-1:-1;24531:1870:3;;;;;11057:118:5;24531:1870:3;;;;;;;3447:784:2;;24531:1870:3;;;;;-1:-1:-1;;;;;;;;;;;24531:1870:3;;;144:391:6;24531:1870:3;;;;;;;;;;;;;;;;;;;144:391:6;;;-1:-1:-1;;144:391:6;;;;4572:5:1;144:391:6;;;;;:::i;:::-;;;12478:70:0;;;:::i;:::-;4572:5:1;:::i;144:391:6:-;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;;:::i;:::-;11247:13:1;144:391:6;;11247:13:1;10859:219;;;;;;;;;10731:353;;11247:13;:21;:26;;144:391:6;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;14880:7:1;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;9831:339:0;;;;144:391:6;9831:339:0;144:391:6;9831:339:0;;;;;;144:391:6;9831:339:0;;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;;144:391:6;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;3502:31:5;144:391:6;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;144:391:6;;;;12478:70:0;;:::i;:::-;144:391:6;4770:437:1;6299::0;;;;;;-1:-1:-1;;;;;6299:437:0;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;;3620:29:5;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;:::o;:::-;;:::i;:::-;-1:-1:-1;;;;;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;144:391:6;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;:::i;:::-;;;;;;-1:-1:-1;;144:391:6;;;;-1:-1:-1;;11523:61:0;144:391:6;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;-1:-1:-1;144:391:6;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;14088:36:5;144:391:6;;;;;:::i;:::-;;;;;14088:36:5;;:::i;:::-;144:391:6;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;;;;;;;;;9797:590:3;;;;;;;-1:-1:-1;9797:590:3;;;;;;-1:-1:-1;9797:590:3;144:391:6;;;;;9797:590:3;;;144:391:6;-1:-1:-1;9797:590:3;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;4770:437:1;;;;-1:-1:-1;4770:437:1;-1:-1:-1;;;144:391:6;4770:437:1;;;;;;;-1:-1:-1;144:391:6;;-1:-1:-1;;;;;144:391:6;;;-1:-1:-1;;;;;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;10297:58:5;;;144:391:6;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;-1:-1:-1;;;;;17705:22:5;144:391:6;;18300:179:3;;;8230:395;;;18300:179;;;;;;;;;;;18166:319;;17705:22:5;144:391:6;17705:32:5;144:391:6;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;11909:5:1;;:::i;:::-;144:391:6;;-1:-1:-1;;;;;144:391:6;;;;;;;9372:19:5;144:391:6;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;3447:784:2;;;144:391:6;;;;;;;;;;9372:19:5;144:391:6;;;;;;;;-1:-1:-1;;144:391:6;;;;9407:41:5;;144:391:6;9407:41:5;144:391:6;;;;;-1:-1:-1;144:391:6;;;;;9372:19:5;144:391:6;;-1:-1:-1;;144:391:6;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;9372:19:5;144:391:6;;;;;;3447:784:2;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;9325:196:3;;;;;-1:-1:-1;9325:196:3;144:391:6;9325:196:3;;;;144:391:6;;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;-1:-1:-1;;;144:391:6;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;12478:70:0;;:::i;:::-;10506:526;;;;-1:-1:-1;10506:526:0;144:391:6;10506:526:0;;;;;;;;;-1:-1:-1;11051:12:0;10506:526;;11051:12;:::i;10506:526::-;;-1:-1:-1;10506:526:0;144:391:6;10506:526:0;;144:391:6;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;12478:70:0;;:::i;:::-;8479:183;;;;;;8681:8;;;:::i;8479:183::-;;-1:-1:-1;8479:183:0;144:391:6;8479:183:0;;144:391:6;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;144:391:6;;;;;;;7186:39:5;;;;:::i;:::-;-1:-1:-1;144:391:6;;;7236:9:5;144:391:6;;;;;;;-1:-1:-1;;;;;;144:391:6;7254:10:5;144:391:6;;;7236:28:5;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;9822:41:5;144:391:6;;;;;;:::i;:::-;11909:5:1;;:::i;:::-;9717:36:5;144:391:6;;-1:-1:-1;;;;;;144:391:6;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;9769:38:5;-1:-1:-1;;9769:38:5;-1:-1:-1;144:391:6;;-1:-1:-1;;144:391:6;;;;9822:41:5;144:391:6;;;;;;;-1:-1:-1;;144:391:6;;;;;;;;;:::i;:::-;11885:237:0;;;-1:-1:-1;11885:237:0;144:391:6;11885:237:0;;;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;144:391:6;12986:13:5;144:391:6;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;12986:13:5;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;3172:1:5:-;;;;;;;;;;;;;:::i;:::-;144:391:6;;3172:1:5;;;;;;;;144:391:6;;;3172:1:5;;-1:-1:-1;;;;;3172:1:5;;;;144:391:6;3172:1:5;;;144:391:6;;;;;3172:1:5;;;;:::o;:::-;;;;-1:-1:-1;;;;;3172:1:5;;;;;;144:391:6;3172:1:5;;144:391:6;3172:1:5;;144:391:6;;;;;;3172:1:5;;;144:391:6;3172:1:5;;;;;;;;;;:::i;:::-;-1:-1:-1;;144:391:6;;;;;;;3172:1:5;;;144:391:6;;;3172:1:5;;;144:391:6;;3172:1:5;;;:::o;5567:367::-;;;5678:10;5692:23;-1:-1:-1;;;;;144:391:6;5678:37:5;144:391:6;;3214:1:5;-1:-1:-1;;;;;5735:22:5;;18300:179:3;;;8230:395;;;18300:179;;;;;;;;;;;18166:319;;5735:22:5;144:391:6;5735:34:5;5731:63;;5841:7;;;:::i;5731:63::-;5778:16;;;;;;;;5674:254;10872:2:3;;;;;;;:::i;:::-;10928:2657;;;;-1:-1:-1;;;5678:10:5;10928:2657:3;;;;;;;;;;;;-1:-1:-1;;;;;10928:2657:3;;;;;;;;;;;;;;;;;;;;;;;;;;;5678:10:5;;10928:2657:3;5678:10:5;;10928:2657:3;;;;;5674:254:5;10928:2657:3;;5674:254:5;10928:2657:3;;;;;;;;;;3447:784:2;;10928:2657:3;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;10928:2657:3;;;5567:367:5:o;10928:2657:3:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6957:332;16167:187;;;;-1:-1:-1;;;16167:187:3;;;;;;;;;-1:-1:-1;;;;;16167:187:3;7115:168;;;;;6957:332::o;7433:533::-;7565:395;;;;8230;;;7565;;;;;;;;;;7433:533;:::o;7565:395::-;;;;;;;144:391:6;;;;;;;;:::o;:::-;9372:19:5;-1:-1:-1;144:391:6;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;144:391:6;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;144:391:6;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;144:391:6;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;4906:23:5;144:391:6;;:::i;:::-;4906:23:5;144:391:6;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;3447:784:2;;;144:391:6;;;;;;;;;;4906:23:5;144:391:6;:::o;:::-;4906:23:5;144:391:6;;-1:-1:-1;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;4906:23:5;144:391:6;:::o;:::-;;;3447:784:2;;144:391:6;;4906:23:5;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;4939:27:5;144:391:6;;:::i;:::-;4939:27:5;144:391:6;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;3447:784:2;;;144:391:6;;;;;;;;;;4939:27:5;144:391:6;:::o;:::-;4939:27:5;144:391:6;;-1:-1:-1;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;4939:27:5;144:391:6;:::o;:::-;;;3447:784:2;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4495:679:5;;;;;;;;;144:391:6;;-1:-1:-1;;;;;144:391:6;;;;;;;4867:29:5;144:391:6;;:::i;:::-;;;;;;;;;;;5064:38:5;144:391:6;;;;;;;4976:36:5;144:391:6;5146:20:5;144:391:6;;;;;;;;;;;3447:784:2;;;144:391:6;;;;;;;;;;4867:29:5;144:391:6;;:::i;:::-;;:::i;:::-;;;;;;;-1:-1:-1;;;;;144:391:6;;4976:36:5;144:391:6;;;4976:36:5;144:391:6;;4976:36:5;5039:13;;;:::i;:::-;144:391:6;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;5064:38:5;5146:20;:::i;144:391:6:-;9372:19:5;144:391:6;;-1:-1:-1;;144:391:6;;;;;;;;;;;;;;;;5146:20:5;144:391:6;;4976:36:5;144:391:6;;;;;;5064:38:5;144:391:6;;;;;;;;;;;;;4867:29:5;144:391:6;;:::i;:::-;;;3447:784:2;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11307:346:5;11391:23;-1:-1:-1;;;;;144:391:6;11377:10:5;:37;11373:67;;144:391:6;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;11505:28:5;;11501:41;;144:391:6;11559:15:5;;144:391:6;;11476:9:5;144:391:6;;;;;;;11559:15:5;144:391:6;;-1:-1:-1;;;;;;144:391:6;;;;;11585:61:5;;;;;144:391:6;;-1:-1:-1;;;11585:61:5;;;;;144:391:6;;;;-1:-1:-1;;144:391:6;;;;;;-1:-1:-1;;11585:61:5;;;;;;;;11307:346;:::o;11585:61::-;;;11531:1;11585:61;;;:::i;11501:41::-;11535:7;;:::o;11373:67::-;11423:17;;;;;;;;14406:249:3;;;14575:2;;;;;:::i;:::-;38334:89;;14588:60;;14406:249;;;;;;:::o;14588:60::-;14606:42;144:391:6;;;;;;:::i;:::-;14606:42:3;;:::i;:::-;14588:60;;;;;;;144:391:6;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;144:391:6;;;;;;;;;;;;;;:::o;12699:332:5:-;15702:194:3;;;;-1:-1:-1;;;15702:194:3;;;;;;;;;;;;;12792:44:5;;12851:16;144:391:6;-1:-1:-1;;;;;144:391:6;;12847:105:5;;13001:22;;12969:55;13001:22;;:::i;:::-;144:391:6;;:::i;:::-;12969:55:5;:::i;12847:105::-;12904:37;;12879:1;;12904:33;;-1:-1:-1;;;;;144:391:6;12904:24:5;-1:-1:-1;;;;;144:391:6;;;12904:33:5;144:391:6;;;;;;;;;;12904:37:5;;;;;144:391:6;;;;;;;;12904:37:5;;;;;;;;;;12879:1;12904:37;;;12897:44;;:::o;12904:37::-;;;;;;12879:1;12904:37;;;;;;:::i;:::-;;;;;:::i;12792:44::-;12817:19;;;;;;;;4659:554:1;4770:437;;;;;;14880:7;4770:437;;;;;;;;4659:554::o;4464:715:2:-;;-1:-1:-1;;;;;4653:520:2;;2531:5;4653:520;;;;;;;;;;;;;4464:715::o;4653:520::-;;-1:-1:-1;4653:520:2;;;;;;-1:-1:-1;4653:520:2;;;;26907:1160:3;27097:964;;;;-1:-1:-1;;;;;27097:964:3;;;-1:-1:-1;;;27097:964:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26907:1160;;;:::o;27097:964::-;;;;;;;;;;26907:1160;;:::o;27097:964::-;;;;;;-1:-1:-1;11535:7:5:o;17625:119::-;18300:179:3;;;;-1:-1:-1;;;18300:179:3;;;;;;;;;;;17705:32:5;;17625:119::o;144:391:6:-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;144:391:6;;;;;;;;;;;;;-1:-1:-1;;;;;144:391:6;3172:1:5;;;144:391:6;;;;;;;;;;;;;;;;;;;;;3172:1:5;;144:391:6;;;;;;;;14897:419:5;144:391:6;;-1:-1:-1;;;15083:60:5;;15137:4;15083:60;;;144:391:6;14897:419:5;;;-1:-1:-1;;;;;15091:23:5;144:391:6;;;14897:419:5;15083:60;144:391:6;;;;15083:60:5;;;;;;;;;15160:149;15083:60;-1:-1:-1;15083:60:5;;;-1:-1:-1;144:391:6;;-1:-1:-1;;;15160:149:5;;144:391:6;;;;;;;15271:10:5;;15083:60;15160:149;;;:::i;:::-;;15205:9;;15160:149;;;;;;;;-1:-1:-1;15160:149:5;;;15153:156;14897:419;:::o;15160:149::-;;;;15083:60;15160:149;15083:60;15160:149;;;;;;;:::i;7292:355:0:-;-1:-1:-1;;7390:251:0;;;;;7292:355::o;32278:3007:3:-;32405:2;;;;;:::i;:::-;144:391:6;32461:2775:3;;;-1:-1:-1;;;32461:2775:3;;;;;;;;;;;-1:-1:-1;;;;;32461:2775:3;;;;;;;;;;;;;;;;;;;;144:391:6;32461:2775:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;3447:784:2;;32461:2775:3;;;;;;144:391:6;32461:2775:3;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;144:391:6;32461:2775:3;;32278:3007::o;38588:1370::-;;38750:1202;;38588:1370;;38750:1202;;;;;;;;;;;;;144:391:6;;;;;38750:1202:3;;;;;;;;;;;;;;;;;;;;;;;;;;38588:1370;38750:1202;;;;;;;;;;;;;;38588:1370;38750:1202;-1:-1:-1;;;38750:1202:3;;;38588:1370::o;38750:1202::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24332:2127;24475:2;24414:11;;;;:::i;24475:2::-;144:391:6;24531:1870:3;;;-1:-1:-1;;;24531:1870:3;;;;;;;;;;;;-1:-1:-1;;;;;24531:1870:3;;;;;;;;144:391:6;24531:1870:3;;;;;;;;;;;;;;24332:2127;24531:1870;144:391:6;24531:1870:3;;;;;24332:2127;24531:1870;;;;;;;3447:784:2;;24531:1870:3;;;;;-1:-1:-1;;;;;;;;;;;24531:1870:3;;;24332:2127::o;24531:1870::-;;;;;;;;;;;;;;;;;;;6145:1089:0;144:391:6;;;;;6299:437:0;;4770::1;6299::0;;;;;;;;;;;-1:-1:-1;;6299:437:0;6145:1089::o;4883:1190::-;-1:-1:-1;;5044:589:0;;;-1:-1:-1;;;;;5044:589:0;;;;;;;-1:-1:-1;;5044:589:0;;;;;;4883:1190::o;5044:589::-;;;;;;;144:391:6;-1:-1:-1;;;;;144:391:6;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;144:391:6;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;:::o;16187:900:5:-;;;;16333:16;;;:::i;:::-;16380:1;16419:29;;;;:::i;:::-;16464:17;16483:9;;;;;;;16933:25;;;;;;;:::i;:::-;16973:13;16380:1;16988:14;;;;;;-1:-1:-1;17067:13:5;;-1:-1:-1;;16187:900:5:o;17004:3::-;17035:11;;144:391:6;17035:11:5;;;:::i;:::-;144:391:6;17023:23:5;;;;:::i;:::-;144:391:6;;16973:13:5;;16494:3;16167:187:3;;;;-1:-1:-1;;;16167:187:3;;;;;;;;;;-1:-1:-1;;;;;144:391:6;;;16167:187:3;;16517:20:5;16513:272;;16494:3;;;;:::i;:::-;16464:17;;16513:272;16557:24;;;;144:391:6;16557:24:5;;;:::i;:::-;144:391:6;;16685:28:5;;;;16513:272;16681:90;16737:15;;;;;:::o;3513:1560:4:-;;3644:1423;;;;;;;;;;;;;;;;;-1:-1:-1;;3644:1423:4;;;;;;;;;;;;;;;;;;;;;;;;;;;144:391:6;;;3644:1423:4;;;;3513:1560::o;38748:1214::-;38924:1032;;;;;;38748:1214;38924:1032;;;;;-1:-1:-1;;38924:1032:4;;;;;;;;;;-1:-1:-1;;38924:1032:4;;;;;;;;;;-1:-1:-1;;38924:1032:4;;;;;;;;;-1:-1:-1;;38924:1032:4;;;;;;;;;;-1:-1:-1;;38924:1032:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38748:1214::o;144:391:6:-;;;;;;;;;18731:2:5;144:391:6;;;;;;;:::o;:::-;18720:4:5;144:391:6;;;18720:4:5;144:391:6;;;:::o;18059:783:5:-;18140:4;17985:62;144:391:6;;18181:10:5;18167:24;;18181:10;;-1:-1:-1;18335:19:5;18349:4;17985:62;18326:4;17985:62;-1:-1:-1;;;;;144:391:6;18335:19:5;:::i;18163:673::-;18390:10;18376:24;18390:10;;18434:23;-1:-1:-1;;;;;144:391:6;18420:10:5;:37;18416:67;;18537:4;17985:62;18608:4;17985:62;-1:-1:-1;;;;;144:391:6;18140:4:5;18650:18;;;;;;18372:464;;;18059:783::o;18670:3::-;18727:6;18736:11;18727:6;18720:13;18727:6;144:391:6;18727:6:5;;:::i;:::-;18720:13;:::i;:::-;17985:62;18736:11;:::i;:::-;144:391:6;18635:13:5;;18372:464;18800:25;;;18140:4;18800:25;;18140:4;18800:25;3116:967:1;3246:831;;;4572:5;3246:831;;;;;;;;;;;;;;;;;;;4572:5;3246:831;;3116:967::o;144:391:6:-;-1:-1:-1;;;;;144:391:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;17170:449:5:-;17294:23;-1:-1:-1;;;;;144:391:6;17280:10:5;:37;17276:337;;17170:449;;:::o;17276:337::-;17337:16;;;:::i;:::-;:38;;;;17276:337;17333:101;;144:391:6;;-1:-1:-1;;;;;144:391:6;;17448:155:5;;17276:337;17170:449;;:::o;17448:155::-;17503:54;;-1:-1:-1;;;;;144:391:6;17503:37:5;144:391:6;17503:54:5;:85;;;;;;144:391:6;;-1:-1:-1;;;17503:85:5;;144:391:6;;;;;;;;;17503:85:5;;144:391:6;;17280:10:5;17503:85;;;;:::i;:::-;;;;;;;;;;;17170:449;:::o;17337:38::-;-1:-1:-1;;;;;;144:391:6;;17357:18:5;17337:38;;17170:449;17294:23;-1:-1:-1;;;;;144:391:6;17280:10:5;:37;17276:337;;17170:449;;:::o;17276:337::-;17337:16;;;:::i;:::-;:38;;;;17276:337;17333:101;;144:391:6;;-1:-1:-1;;;;;144:391:6;;17448:155:5;;17276:337;17170:449;;:::o;17448:155::-;17503:54;;-1:-1:-1;;;;;144:391:6;17503:37:5;144:391:6;17503:54:5;:85;;;;;;144:391:6;;-1:-1:-1;;;17503:85:5;;144:391:6;;;;;;;;;17503:85:5;;144:391:6;17280:10:5;17503:85;;;;:::i;17337:38::-;;17357:18;17337:38;;17170:449;;;17294:23;-1:-1:-1;;;;;144:391:6;17280:10:5;:37;17276:337;;17170:449;;;:::o;17276:337::-;17337:16;;;:::i;:::-;:38;;;;17276:337;17333:101;;17452:17;144:391:6;-1:-1:-1;;;;;144:391:6;;17448:155:5;;17276:337;;17170:449;;;:::o;17448:155::-;17503:54;;-1:-1:-1;;;;;144:391:6;17503:37:5;144:391:6;17503:54:5;:85;;;;;;144:391:6;17452:17:5;144:391:6;;;;;;;;;;;;;17503:85:5;;17280:10;17503:85;;;;:::i;:::-;;;;;;;;;;;17448:155;;;;;;17503:85;;;17452:17;17503:85;;;:::i;:::-;;;;17337:38;-1:-1:-1;;;;;;144:391:6;;17357:18:5;17337:38;;15594:587;;-1:-1:-1;;;;;17705:22:5;;18300:179:3;;;8230:395;;;18300:179;;;;;;;;;;;18166:319;;17705:22:5;144:391:6;15677:16:5;;16167:187:3;;;;-1:-1:-1;;;16167:187:3;;144:391:6;16167:187:3;;;;;;;;;16093:17:5;;144:391:6;;-1:-1:-1;;;;;16167:187:3;;;;;;;;15831:19:5;;15889:7;;;;;:::i;:::-;18808:307:3;;;8230:395;;;18808:307;;;;;;;;;;;;;;144:391:6;18808:307:3;;;;;;144:391:6;;;;;16093:17:5;15594:587::o;15827:200::-;-1:-1:-1;;;;;144:391:6;;15922:20:5;15918:109;;15827:200;;;;;;15918:109;16004:7;;;:::i;:::-;15918:109;;;;;19609:1653:3;19712:2;;;;:::i;:::-;144:391:6;;;;;19768:1439:3;;19704:1;19768:1439;8230:395;;;19768:1439;;;19704:1;19768:1439;;;;;;;;;;;;;;;;;19704:1;19768:1439;;;;;;;;;;;;;;;;;;19704:1;-1:-1:-1;;;;;;;;;;;19768:1439:3;;;19609:1653::o;19768:1439::-;;;;;;;;;;;;19704:1;19768:1439;;;

Swarm Source

ipfs://2905636dba5b9eeab3dd04124fe5d831f35328386f49e321bcba5a3e3619b831
[ 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.