ETH Price: $2,956.76 (-0.00%)

Token

Metamorph Labs: Inception (MMO)

Overview

Max Total Supply

2,669 MMO

Holders

2,669

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 MMO
0x0886a3b935de1a05dd5067821d5a753656a607a2
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
Metamorph

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Arbiscan.io on 2024-02-16
*/

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

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

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

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

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

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

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

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        /// @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.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            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 {} {
                str := add(str, w) // `sub(str, 1)`.
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory str) {
        if (value >= 0) {
            return toString(uint256(value));
        }
        unchecked {
            str = 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 length := mload(str) // Load the string length.
            mstore(str, 0x2d) // Store the '-' character.
            str := sub(str, 1) // Move back the string pointer by a byte.
            mstore(str, add(length, 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 str) {
        str = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @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` 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 str)
    {
        /// @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.
            str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let start := sub(str, 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 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(str, start)) { break }
            }

            if temp {
                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
            str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := mload(str) // Get the length.
            str := add(str, o) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write 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 str) {
        /// @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.
            str := add(mload(0x40), 0x80)
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            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 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @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 str) {
        str = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(str, 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        /// @solidity memory-safe-assembly
        assembly {
            str := mload(0x40)

            // Allocate the 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(str, 0x80))

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            str := add(str, 2)
            mstore(str, 40)

            let o := add(str, 0x20)
            mstore(add(o, 40), 0)

            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 str) {
        str = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(raw)
            str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(str, add(length, length)) // Store the length of the output.

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let o := add(str, 0x20)
            let end := add(raw, length)

            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 the 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 {
            let mask := shl(7, div(not(0), 255))
            result := 1
            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)
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   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 `search` replaced with `replacement`.
    function replace(string memory subject, string memory search, string memory replacement)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
            mstore(last, 0)
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
            mstore(result, k) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    if iszero(gt(from, subjectLength)) {
                        result := from
                        break
                    }
                    result := subjectLength
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)

                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(add(search, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }

                if iszero(lt(searchLength, 0x20)) {
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let searchLength := mload(search)
                if gt(searchLength, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), searchLength)
                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(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns true if `search` is found in `subject`, false otherwise.
    function contains(string memory subject, string memory search) internal pure returns (bool) {
        return indexOf(subject, search) != NOT_FOUND;
    }

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

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

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(output, 0) // Zeroize the slot after the string.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength) // Store the length.
                // Allocate the memory.
                mstore(0x40, add(result, add(resultLength, 0x20)))
            }
        }
    }

    /// @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 subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) { end := subjectLength }
            if iszero(gt(subjectLength, start)) { start := subjectLength }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
            }
        }
    }

    /// @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, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 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))
            let prevIndex := 0
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)
                }
                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 {
            let w := not(0x1f)
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLength, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, aLength)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLength, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 0x1f), w))
        }
    }

    /// @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 length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                let w := not(0)
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    if iszero(o) { break }
                }
                result := mload(0x40)
                mstore(result, length) // Store the length.
                let last := add(add(result, 0x20), length)
                mstore(last, 0) // Zeroize the slot after the string.
                mstore(0x40, add(last, 0x20)) // Allocate the 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)
            let o := add(result, 0x20)
            mstore(o, s)
            mstore(add(o, n), 0)
            mstore(0x40, add(result, 0x40))
        }
    }

    /// @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 {
            let end := add(s, mload(s))
            result := add(mload(0x40), 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(result, c)
                    result := add(result, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 0x1f)))
                result := add(result, shr(5, t))
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the 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 {
            let end := add(s, mload(s))
            result := add(mload(0x40), 0x20)
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            // 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 {} 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(result, c)
                        result := add(result, 1)
                        continue
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c)
                    result := add(result, 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(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the 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 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 {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @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 aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes of `a` and `b`.
                    or(
                        shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
                        mload(sub(add(b, 0x1e), aLength))
                    ),
                    // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLength, 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 {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            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 retSize := 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, retSize), 0)
            // Store the return offset.
            mstore(retStart, 0x20)
            // End the transaction, returning the string.
            return(retStart, retSize)
        }
    }
}

contract Metamorph is ERC721, Ownable {
    using LibString for uint256;
    using LibString for string;

    error Locked();
    error TransferFailed();
    error SupplyCapReached();
    error InsufficientPayment();

    event URILocked();
    event MintOpened();
    event MintClosed();
    event SupplyUpdate(uint16 indexed newMaxSupply);
    event UpdateBaseURI(string indexed baseURI_);
    event Withdraw(address indexed to, uint256 indexed amount);

    string internal _name;
    string internal _symbol;
    string internal _baseURI;
    uint16 internal _mintedSupply;
    uint16 public maxSupply;
    uint16 public totalSupply;
    uint64 public immutable price;
    bool mintActive = true;
    bool uriLocked;

    constructor(
        address owner_,
        string memory name_,
        string memory symbol_,
        string memory baseURI_,
        uint16 maxSupply_,
        uint64 price_
    ) {
        _initializeOwner(owner_);
        _name = name_;
        _symbol = symbol_;
        _baseURI = baseURI_;
        maxSupply = maxSupply_;
        price = price_;
        emit UpdateBaseURI(baseURI_);
    }

    function name() public view override returns (string memory) {
        return _name;
    }

    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    function contractURI() external view returns (string memory) {
        return _baseURI.concat("contract.json");
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        if (!_exists(tokenId)) return "";
        else return _baseURI.concat(tokenId.toString());
    }

    function __mint(address to, uint16 amount) internal {
        uint16 currentSupply = _mintedSupply;
        if (!mintActive) revert Locked();
        if (msg.value < price) revert InsufficientPayment();
        if (currentSupply + amount > maxSupply) revert SupplyCapReached();
        for (uint16 i; i < amount;) {
            unchecked {
                _mint(to, ++currentSupply);
                ++i;
            }
        }
        unchecked {
            totalSupply += amount;
            _mintedSupply += amount;
        }
    }

    function airdrop(address to, uint16 amount) external onlyOwner {
        
        uint16 currentSupply = _mintedSupply;
        if (!mintActive) revert Locked();
        if (currentSupply + amount > maxSupply) revert SupplyCapReached();
        for (uint16 i; i < amount;) {
            unchecked {
                _mint(to, ++currentSupply);
                ++i;
            }
        }
        unchecked {
            totalSupply += amount;
            _mintedSupply += amount;
        }
    }

    function burn(uint256 tokenId) external {
        if (!_isApprovedOrOwner(msg.sender, tokenId)) revert Unauthorized();
        _burn(tokenId);
        unchecked {
            totalSupply -= 1;
        }
    }

    function openMint() external onlyOwner {
        mintActive = true;
        emit MintOpened();
    }

    function closeMint() external onlyOwner {
        mintActive = false;
        emit MintClosed();

        uint16 supply = totalSupply;
        if (supply < maxSupply) {
            maxSupply = supply;
            emit SupplyUpdate(supply);
        }
    }

    function updateBaseURI(string memory baseURI_) external onlyOwner {
        if (uriLocked) revert Locked();
        _baseURI = baseURI_;
        emit UpdateBaseURI(baseURI_);
    }

    function lockURI() public onlyOwner {
        uriLocked = true;
        emit URILocked();
    }

    function withdrawETH(address to) external onlyOwner {
        uint256 amount = address(this).balance;
        (bool success,) = payable(to).call{value: amount}("");
        if (!success) revert TransferFailed();
        emit Withdraw(to, amount);
    }

    function renounceOwnership() public payable override onlyOwner {
        if (!uriLocked) lockURI();
        super.renounceOwnership();
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"uint16","name":"maxSupply_","type":"uint16"},{"internalType":"uint64","name":"price_","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"SupplyCapReached","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFailed","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":[],"name":"MintClosed","type":"event"},{"anonymous":false,"inputs":[],"name":"MintOpened","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":"uint16","name":"newMaxSupply","type":"uint16"}],"name":"SupplyUpdate","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":[],"name":"URILocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"baseURI_","type":"string"}],"name":"UpdateBaseURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","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":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"closeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","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":[],"name":"lockURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openMint","outputs":[],"stateMutability":"nonpayable","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":[],"name":"price","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","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":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"updateBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040526003805460ff60301b1916660100000000000017905534801562000026575f80fd5b5060405162001be538038062001be583398101604081905262000049916200021f565b6200005486620000f0565b5f62000061868262000377565b50600162000070858262000377565b5060026200007f848262000377565b506003805463ffff000019166201000061ffff8516021790556001600160401b038116608052604051620000b590849062000443565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250505050505062000460565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200015b57818101518382015260200162000141565b50505f910152565b5f82601f83011262000173575f80fd5b81516001600160401b03808211156200019057620001906200012b565b604051601f8301601f19908116603f01168101908282118183101715620001bb57620001bb6200012b565b81604052838152866020858801011115620001d4575f80fd5b620001e78460208301602089016200013f565b9695505050505050565b805161ffff8116811462000203575f80fd5b919050565b80516001600160401b038116811462000203575f80fd5b5f805f805f8060c0878903121562000235575f80fd5b86516001600160a01b03811681146200024c575f80fd5b60208801519096506001600160401b038082111562000269575f80fd5b620002778a838b0162000163565b965060408901519150808211156200028d575f80fd5b6200029b8a838b0162000163565b95506060890151915080821115620002b1575f80fd5b50620002c089828a0162000163565b935050620002d160808801620001f1565b9150620002e160a0880162000208565b90509295509295509295565b600181811c908216806200030257607f821691505b6020821081036200032157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200037257805f5260205f20601f840160051c810160208510156200034e5750805b601f840160051c820191505b818110156200036f575f81556001016200035a565b50505b505050565b81516001600160401b038111156200039357620003936200012b565b620003ab81620003a48454620002ed565b8462000327565b602080601f831160018114620003e1575f8415620003c95750858301515b5f19600386901b1c1916600185901b1785556200043b565b5f85815260208120601f198616915b828110156200041157888601518255948401946001909101908401620003f0565b50858210156200042f57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8251620004568184602087016200013f565b9190910192915050565b60805161176c620004795f395f610413015261176c5ff3fe6080604052600436106101d0575f3560e01c80638da5cb5b116100fd578063c87b56dd11610092578063ec8d130b11610062578063ec8d130b1461051b578063f04e283e1461053a578063f2fde38b1461054d578063fee81cf414610560575f80fd5b8063c87b56dd14610494578063d5abeb01146104b3578063e8a3d485146104d3578063e985e9c5146104e7575f80fd5b8063a035b1fe116100cd578063a035b1fe14610402578063a22cb4651461044e578063b88d4fde1461046d578063bce6d67214610480575f80fd5b80638da5cb5b146103a35780638e021c06146103bb578063931688cb146103cf57806395d89b41146103ee575f80fd5b806342842e0e1161017357806364f101f01161014357806364f101f01461033b578063690d83201461034f57806370a082311461036e578063715018a61461039b575f80fd5b806342842e0e146102e257806342966c68146102f557806354d1f13d146103145780636352211e1461031c575f80fd5b8063095ea7b3116101ae578063095ea7b31461027d57806318160ddd1461029257806323b872dd146102c757806325692962146102da575f80fd5b806301ffc9a7146101d457806306fdde0314610225578063081812fc14610246575b5f80fd5b3480156101df575f80fd5b506102106101ee3660046112a0565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b348015610230575f80fd5b50610239610591565b60405161021c91906112f0565b348015610251575f80fd5b50610265610260366004611322565b610620565b6040516001600160a01b03909116815260200161021c565b61029061028b36600461134f565b61065b565b005b34801561029d575f80fd5b506003546102b490640100000000900461ffff1681565b60405161ffff909116815260200161021c565b6102906102d5366004611377565b61066a565b610290610764565b6102906102f0366004611377565b6107b1565b348015610300575f80fd5b5061029061030f366004611322565b6107dd565b610290610837565b348015610327575f80fd5b50610265610336366004611322565b610870565b348015610346575f80fd5b506102906108ac565b34801561035a575f80fd5b506102906103693660046113b0565b610955565b348015610379575f80fd5b5061038d6103883660046113b0565b610a08565b60405190815260200161021c565b610290610a40565b3480156103ae575f80fd5b50638b78c6d81954610265565b3480156103c6575f80fd5b50610290610a6b565b3480156103da575f80fd5b506102906103e93660046113dd565b610ab4565b3480156103f9575f80fd5b50610239610b34565b34801561040d575f80fd5b506104357f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff909116815260200161021c565b348015610459575f80fd5b50610290610468366004611488565b610b43565b61029061047b3660046114c1565b610b96565b34801561048b575f80fd5b50610290610bf0565b34801561049f575f80fd5b506102396104ae366004611322565b610c3b565b3480156104be575f80fd5b506003546102b49062010000900461ffff1681565b3480156104de575f80fd5b50610239610d24565b3480156104f2575f80fd5b50610210610501366004611554565b601c52670a5a2e7a000000006008525f526030600c205490565b348015610526575f80fd5b50610290610535366004611585565b610d61565b6102906105483660046113b0565b610e44565b61029061055b3660046113b0565b610e7e565b34801561056b575f80fd5b5061038d61057a3660046113b0565b63389a75e1600c9081525f91909152602090205490565b60605f805461059f906115b5565b80601f01602080910402602001604051908101604052809291908181526020018280546105cb906115b5565b80156106165780601f106105ed57610100808354040283529160200191610616565b820191905f5260205f20905b8154815290600101906020018083116105f957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b6106515763ceea21b65f526004601cfd5b6001015492915050565b610666338383610ea4565b5050565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b0394851694938416938116919082861483026106bb5767ceea21b6a1148100831560021b526004601cfd5b855f5281600101549250823314863314176106e7576030600c20546106e757634b6e7f185f526004601cfd5b82156106f4575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff811684026107355767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b6107bc83838361066a565b813b1561075f5761075f83838360405180602001604052805f815250610f3e565b6107e73382610fc7565b610803576040516282b42960e81b815260040160405180910390fd5b61080c81611030565b50600380545f1961ffff640100000000808404821692909201160265ffff0000000019909116179055565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806108a75763ceea21b65f526004601cfd5b919050565b6108b461103a565b6003805466ff000000000000191690556040517f589ed34b6de61e6df418b1c0e5caa881461804657f37544ca23bf0b86d09f1e3905f90a160035461ffff640100000000820481169162010000900416811015610952576003805463ffff000019166201000061ffff8416908102919091179091556040517f52517e69d79a4e16171442bbef42454bad6689798f61eaecf3825e939ccb2367905f90a25b50565b61095d61103a565b60405147905f906001600160a01b0384169083908381818185875af1925050503d805f81146109a7576040519150601f19603f3d011682016040523d82523d5f602084013e6109ac565b606091505b50509050806109ce576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038516907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364905f90a3505050565b5f81610a1b57638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b610a4861103a565b600354600160381b900460ff16610a6157610a61610a6b565b610a69611054565b565b610a7361103a565b6003805467ff000000000000001916600160381b1790556040517f31d1c0a3af6e15844ff9c1bf6201a5cf123137eb2fb3eeb96861a436d49cd25f905f90a1565b610abc61103a565b600354600160381b900460ff1615610ae7576040516303cb96db60e21b815260040160405180910390fd5b6002610af38282611631565b5080604051610b0291906116ed565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250565b60606001805461059f906115b5565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b610ba185858561066a565b833b15610be957610be985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610f3e92505050565b5050505050565b610bf861103a565b6003805466ff000000000000191666010000000000001790556040517f4301b55b3d4fd9018308a6bd66bf37880623a9548566d1b12867ab619a993ca1905f90a1565b6060610c64825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b610c7b57505060408051602081019091525f815290565b610d1e610c8783611065565b60028054610c94906115b5565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc0906115b5565b8015610d0b5780601f10610ce257610100808354040283529160200191610d0b565b820191905f5260205f20905b815481529060010190602001808311610cee57829003601f168201915b50505050506110a790919063ffffffff16565b92915050565b6060610d5c6040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b81525060028054610c94906115b5565b905090565b610d6961103a565b60035461ffff8116906601000000000000900460ff16610d9c576040516303cb96db60e21b815260040160405180910390fd5b60035462010000900461ffff16610db38383611708565b61ffff161115610dd6576040516354db2d5d60e11b815260040160405180910390fd5b5f5b8261ffff168161ffff161015610e0457610dfc848360010193508361ffff16611101565b600101610dd8565b50506003805461ffff64010000000080830482168501821602808216828416179094011661ffff1990931665ffff0000ffff199091161791909117905550565b610e4c61103a565b63389a75e1600c52805f526020600c208054421115610e7257636f5e88185f526004601cfd5b5f90556109528161119d565b610e8661103a565b8060601b610e9b57637448fbae5f526004601cfd5b6109528161119d565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f208201820180548216915081610ee75763ceea21b65f526004601cfd5b818514851517610f0b57815f526030600c2054610f0b57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f85578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1610fa6573d15610fa6573d5f843e3d83fd5b508060e01b825114610fbf5763d1a57ed65f526004601cfd5b505050505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193600192168061100a5763ceea21b65f526004601cfd5b80851461102857805f526030600c2054611028578160010154851492505b505092915050565b6109525f826111da565b638b78c6d819543314610a69576382b429005f526004601cfd5b61105c61103a565b610a695f61119d565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a90048061107e575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806110b7575083518184018360208301165b86810151828201528401806110d35750505f910183810160208101929092528352603f011660405292915050565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b1561113c5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026111705767ea553b3401336cea841560021b526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f6111e482610870565b9050505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112295763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611256576030600c205461125657634b6e7f185f526004601cfd5b8015611263575f83600101555b5082189055601c600c2080545f19019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b5f602082840312156112b0575f80fd5b81356001600160e01b0319811681146112c7575f80fd5b9392505050565b5f5b838110156112e85781810151838201526020016112d0565b50505f910152565b602081525f825180602084015261130e8160408501602087016112ce565b601f01601f19169190910160400192915050565b5f60208284031215611332575f80fd5b5035919050565b80356001600160a01b03811681146108a7575f80fd5b5f8060408385031215611360575f80fd5b61136983611339565b946020939093013593505050565b5f805f60608486031215611389575f80fd5b61139284611339565b92506113a060208501611339565b9150604084013590509250925092565b5f602082840312156113c0575f80fd5b6112c782611339565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156113ed575f80fd5b813567ffffffffffffffff80821115611404575f80fd5b818401915084601f830112611417575f80fd5b813581811115611429576114296113c9565b604051601f8201601f19908116603f01168101908382118183101715611451576114516113c9565b81604052828152876020848701011115611469575f80fd5b826020860160208301375f928101602001929092525095945050505050565b5f8060408385031215611499575f80fd5b6114a283611339565b9150602083013580151581146114b6575f80fd5b809150509250929050565b5f805f805f608086880312156114d5575f80fd5b6114de86611339565b94506114ec60208701611339565b935060408601359250606086013567ffffffffffffffff8082111561150f575f80fd5b818801915088601f830112611522575f80fd5b813581811115611530575f80fd5b896020828501011115611541575f80fd5b9699959850939650602001949392505050565b5f8060408385031215611565575f80fd5b61156e83611339565b915061157c60208401611339565b90509250929050565b5f8060408385031215611596575f80fd5b61159f83611339565b9150602083013561ffff811681146114b6575f80fd5b600181811c908216806115c957607f821691505b6020821081036115e757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561075f57805f5260205f20601f840160051c810160208510156116125750805b601f840160051c820191505b81811015610be9575f815560010161161e565b815167ffffffffffffffff81111561164b5761164b6113c9565b61165f8161165984546115b5565b846115ed565b602080601f831160018114611692575f841561167b5750858301515b5f19600386901b1c1916600185901b178555610fbf565b5f85815260208120601f198616915b828110156116c0578886015182559484019460019091019084016116a1565b50858210156116dd57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82516116fe8184602087016112ce565b9190910192915050565b61ffff81811683821601908082111561172f57634e487b7160e01b5f52601160045260245ffd5b509291505056fea2646970667358221220500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de64736f6c6343000818003300000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e311000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000194d6574616d6f727068204c6162733a20496e63657074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000034d4d4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961766d7363697366626371663779736c6532686664796271366176653637706966767a627a6a62786a3361347270626c626e6a792f0000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106101d0575f3560e01c80638da5cb5b116100fd578063c87b56dd11610092578063ec8d130b11610062578063ec8d130b1461051b578063f04e283e1461053a578063f2fde38b1461054d578063fee81cf414610560575f80fd5b8063c87b56dd14610494578063d5abeb01146104b3578063e8a3d485146104d3578063e985e9c5146104e7575f80fd5b8063a035b1fe116100cd578063a035b1fe14610402578063a22cb4651461044e578063b88d4fde1461046d578063bce6d67214610480575f80fd5b80638da5cb5b146103a35780638e021c06146103bb578063931688cb146103cf57806395d89b41146103ee575f80fd5b806342842e0e1161017357806364f101f01161014357806364f101f01461033b578063690d83201461034f57806370a082311461036e578063715018a61461039b575f80fd5b806342842e0e146102e257806342966c68146102f557806354d1f13d146103145780636352211e1461031c575f80fd5b8063095ea7b3116101ae578063095ea7b31461027d57806318160ddd1461029257806323b872dd146102c757806325692962146102da575f80fd5b806301ffc9a7146101d457806306fdde0314610225578063081812fc14610246575b5f80fd5b3480156101df575f80fd5b506102106101ee3660046112a0565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b348015610230575f80fd5b50610239610591565b60405161021c91906112f0565b348015610251575f80fd5b50610265610260366004611322565b610620565b6040516001600160a01b03909116815260200161021c565b61029061028b36600461134f565b61065b565b005b34801561029d575f80fd5b506003546102b490640100000000900461ffff1681565b60405161ffff909116815260200161021c565b6102906102d5366004611377565b61066a565b610290610764565b6102906102f0366004611377565b6107b1565b348015610300575f80fd5b5061029061030f366004611322565b6107dd565b610290610837565b348015610327575f80fd5b50610265610336366004611322565b610870565b348015610346575f80fd5b506102906108ac565b34801561035a575f80fd5b506102906103693660046113b0565b610955565b348015610379575f80fd5b5061038d6103883660046113b0565b610a08565b60405190815260200161021c565b610290610a40565b3480156103ae575f80fd5b50638b78c6d81954610265565b3480156103c6575f80fd5b50610290610a6b565b3480156103da575f80fd5b506102906103e93660046113dd565b610ab4565b3480156103f9575f80fd5b50610239610b34565b34801561040d575f80fd5b506104357f000000000000000000000000000000000000000000000000016345785d8a000081565b60405167ffffffffffffffff909116815260200161021c565b348015610459575f80fd5b50610290610468366004611488565b610b43565b61029061047b3660046114c1565b610b96565b34801561048b575f80fd5b50610290610bf0565b34801561049f575f80fd5b506102396104ae366004611322565b610c3b565b3480156104be575f80fd5b506003546102b49062010000900461ffff1681565b3480156104de575f80fd5b50610239610d24565b3480156104f2575f80fd5b50610210610501366004611554565b601c52670a5a2e7a000000006008525f526030600c205490565b348015610526575f80fd5b50610290610535366004611585565b610d61565b6102906105483660046113b0565b610e44565b61029061055b3660046113b0565b610e7e565b34801561056b575f80fd5b5061038d61057a3660046113b0565b63389a75e1600c9081525f91909152602090205490565b60605f805461059f906115b5565b80601f01602080910402602001604051908101604052809291908181526020018280546105cb906115b5565b80156106165780601f106105ed57610100808354040283529160200191610616565b820191905f5260205f20905b8154815290600101906020018083116105f957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b6106515763ceea21b65f526004601cfd5b6001015492915050565b610666338383610ea4565b5050565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b0394851694938416938116919082861483026106bb5767ceea21b6a1148100831560021b526004601cfd5b855f5281600101549250823314863314176106e7576030600c20546106e757634b6e7f185f526004601cfd5b82156106f4575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff811684026107355767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b6107bc83838361066a565b813b1561075f5761075f83838360405180602001604052805f815250610f3e565b6107e73382610fc7565b610803576040516282b42960e81b815260040160405180910390fd5b61080c81611030565b50600380545f1961ffff640100000000808404821692909201160265ffff0000000019909116179055565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806108a75763ceea21b65f526004601cfd5b919050565b6108b461103a565b6003805466ff000000000000191690556040517f589ed34b6de61e6df418b1c0e5caa881461804657f37544ca23bf0b86d09f1e3905f90a160035461ffff640100000000820481169162010000900416811015610952576003805463ffff000019166201000061ffff8416908102919091179091556040517f52517e69d79a4e16171442bbef42454bad6689798f61eaecf3825e939ccb2367905f90a25b50565b61095d61103a565b60405147905f906001600160a01b0384169083908381818185875af1925050503d805f81146109a7576040519150601f19603f3d011682016040523d82523d5f602084013e6109ac565b606091505b50509050806109ce576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038516907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364905f90a3505050565b5f81610a1b57638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b610a4861103a565b600354600160381b900460ff16610a6157610a61610a6b565b610a69611054565b565b610a7361103a565b6003805467ff000000000000001916600160381b1790556040517f31d1c0a3af6e15844ff9c1bf6201a5cf123137eb2fb3eeb96861a436d49cd25f905f90a1565b610abc61103a565b600354600160381b900460ff1615610ae7576040516303cb96db60e21b815260040160405180910390fd5b6002610af38282611631565b5080604051610b0291906116ed565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250565b60606001805461059f906115b5565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b610ba185858561066a565b833b15610be957610be985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610f3e92505050565b5050505050565b610bf861103a565b6003805466ff000000000000191666010000000000001790556040517f4301b55b3d4fd9018308a6bd66bf37880623a9548566d1b12867ab619a993ca1905f90a1565b6060610c64825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b610c7b57505060408051602081019091525f815290565b610d1e610c8783611065565b60028054610c94906115b5565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc0906115b5565b8015610d0b5780601f10610ce257610100808354040283529160200191610d0b565b820191905f5260205f20905b815481529060010190602001808311610cee57829003601f168201915b50505050506110a790919063ffffffff16565b92915050565b6060610d5c6040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b81525060028054610c94906115b5565b905090565b610d6961103a565b60035461ffff8116906601000000000000900460ff16610d9c576040516303cb96db60e21b815260040160405180910390fd5b60035462010000900461ffff16610db38383611708565b61ffff161115610dd6576040516354db2d5d60e11b815260040160405180910390fd5b5f5b8261ffff168161ffff161015610e0457610dfc848360010193508361ffff16611101565b600101610dd8565b50506003805461ffff64010000000080830482168501821602808216828416179094011661ffff1990931665ffff0000ffff199091161791909117905550565b610e4c61103a565b63389a75e1600c52805f526020600c208054421115610e7257636f5e88185f526004601cfd5b5f90556109528161119d565b610e8661103a565b8060601b610e9b57637448fbae5f526004601cfd5b6109528161119d565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f208201820180548216915081610ee75763ceea21b65f526004601cfd5b818514851517610f0b57815f526030600c2054610f0b57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f85578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1610fa6573d15610fa6573d5f843e3d83fd5b508060e01b825114610fbf5763d1a57ed65f526004601cfd5b505050505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193600192168061100a5763ceea21b65f526004601cfd5b80851461102857805f526030600c2054611028578160010154851492505b505092915050565b6109525f826111da565b638b78c6d819543314610a69576382b429005f526004601cfd5b61105c61103a565b610a695f61119d565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a90048061107e575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806110b7575083518184018360208301165b86810151828201528401806110d35750505f910183810160208101929092528352603f011660405292915050565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b1561113c5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026111705767ea553b3401336cea841560021b526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f6111e482610870565b9050505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112295763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611256576030600c205461125657634b6e7f185f526004601cfd5b8015611263575f83600101555b5082189055601c600c2080545f19019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b5f602082840312156112b0575f80fd5b81356001600160e01b0319811681146112c7575f80fd5b9392505050565b5f5b838110156112e85781810151838201526020016112d0565b50505f910152565b602081525f825180602084015261130e8160408501602087016112ce565b601f01601f19169190910160400192915050565b5f60208284031215611332575f80fd5b5035919050565b80356001600160a01b03811681146108a7575f80fd5b5f8060408385031215611360575f80fd5b61136983611339565b946020939093013593505050565b5f805f60608486031215611389575f80fd5b61139284611339565b92506113a060208501611339565b9150604084013590509250925092565b5f602082840312156113c0575f80fd5b6112c782611339565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156113ed575f80fd5b813567ffffffffffffffff80821115611404575f80fd5b818401915084601f830112611417575f80fd5b813581811115611429576114296113c9565b604051601f8201601f19908116603f01168101908382118183101715611451576114516113c9565b81604052828152876020848701011115611469575f80fd5b826020860160208301375f928101602001929092525095945050505050565b5f8060408385031215611499575f80fd5b6114a283611339565b9150602083013580151581146114b6575f80fd5b809150509250929050565b5f805f805f608086880312156114d5575f80fd5b6114de86611339565b94506114ec60208701611339565b935060408601359250606086013567ffffffffffffffff8082111561150f575f80fd5b818801915088601f830112611522575f80fd5b813581811115611530575f80fd5b896020828501011115611541575f80fd5b9699959850939650602001949392505050565b5f8060408385031215611565575f80fd5b61156e83611339565b915061157c60208401611339565b90509250929050565b5f8060408385031215611596575f80fd5b61159f83611339565b9150602083013561ffff811681146114b6575f80fd5b600181811c908216806115c957607f821691505b6020821081036115e757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561075f57805f5260205f20601f840160051c810160208510156116125750805b601f840160051c820191505b81811015610be9575f815560010161161e565b815167ffffffffffffffff81111561164b5761164b6113c9565b61165f8161165984546115b5565b846115ed565b602080601f831160018114611692575f841561167b5750858301515b5f19600386901b1c1916600185901b178555610fbf565b5f85815260208120601f198616915b828110156116c0578886015182559484019460019091019084016116a1565b50858210156116dd57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82516116fe8184602087016112ce565b9190910192915050565b61ffff81811683821601908082111561172f57634e487b7160e01b5f52601160045260245ffd5b509291505056fea2646970667358221220500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de64736f6c63430008180033

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

00000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e311000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000194d6574616d6f727068204c6162733a20496e63657074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000034d4d4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961766d7363697366626371663779736c6532686664796271366176653637706966767a627a6a62786a3361347270626c626e6a792f0000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : owner_ (address): 0x43c5465b85F55753CddCaa1Df33D28B4A56E3110
Arg [1] : name_ (string): Metamorph Labs: Inception
Arg [2] : symbol_ (string): MMO
Arg [3] : baseURI_ (string): ipfs://bafybeiavmscisfbcqf7ysle2hfdybq6ave67pifvzbzjbxj3a4rpblbnjy/
Arg [4] : maxSupply_ (uint16): 3000
Arg [5] : price_ (uint64): 100000000000000000

-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 00000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e3110
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000bb8
Arg [5] : 000000000000000000000000000000000000000000000000016345785d8a0000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [7] : 4d6574616d6f727068204c6162733a20496e63657074696f6e00000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 4d4d4f0000000000000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000043
Arg [11] : 697066733a2f2f6261667962656961766d7363697366626371663779736c6532
Arg [12] : 686664796271366176653637706966767a627a6a62786a3361347270626c626e
Arg [13] : 6a792f0000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

104194:4092:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13801:387;;;;;;;;;;-1:-1:-1;13801:387:0;;;;;:::i;:::-;14119:10;13982:3;13978:21;;;;14113:17;;;14138:10;14132:17;;14110:40;14158:10;14152:17;;;14107:63;;13801:387;;;;470:14:1;;463:22;445:41;;433:2;418:18;13801:387:0;;;;;;;;105367:92;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;6874:544::-;;;;;;;;;;-1:-1:-1;6874:544:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1502:32:1;;;1484:51;;1472:2;1457:18;6874:544:0;1338:203:1;7722:121:0;;;;;;:::i;:::-;;:::i;:::-;;104826:25;;;;;;;;;;-1:-1:-1;104826:25:0;;;;;;;;;;;;;;2157:6:1;2145:19;;;2127:38;;2115:2;2100:18;104826:25:0;1983:188:1;9595:2944:0;;;;;;:::i;:::-;;:::i;48099:630::-;;;:::i;12613:201::-;;;;;;:::i;:::-;;:::i;106972:214::-;;;;;;;;;;-1:-1:-1;106972:214:0;;;;;:::i;:::-;;:::i;48814:466::-;;;:::i;5699:341::-;;;;;;;;;;-1:-1:-1;5699:341:0;;;;;:::i;:::-;;:::i;107305:264::-;;;;;;;;;;;;;:::i;107875:257::-;;;;;;;;;;-1:-1:-1;107875:257:0;;;;;:::i;:::-;;:::i;6190:545::-;;;;;;;;;;-1:-1:-1;6190:545:0;;;;;:::i;:::-;;:::i;:::-;;;2846:25:1;;;2834:2;2819:18;6190:545:0;2700:177:1;108140:143:0;;;:::i;50539:187::-;;;;;;;;;;-1:-1:-1;;;50690:18:0;50539:187;;107769:98;;;;;;;;;;;;;:::i;107577:184::-;;;;;;;;;;-1:-1:-1;107577:184:0;;;;;:::i;:::-;;:::i;105467:96::-;;;;;;;;;;;;;:::i;104858:29::-;;;;;;;;;;;;;;;;;;4115:18:1;4103:31;;;4085:50;;4073:2;4058:18;104858:29:0;3941:200:1;8487:741:0;;;;;;;;;;-1:-1:-1;8487:741:0;;;;;:::i;:::-;;:::i;13331:256::-;;;;;;:::i;:::-;;:::i;107194:103::-;;;;;;;;;;;;;:::i;105698:189::-;;;;;;;;;;-1:-1:-1;105698:189:0;;;;;:::i;:::-;;:::i;104796:23::-;;;;;;;;;;-1:-1:-1;104796:23:0;;;;;;;;;;;105571:119;;;;;;;;;;;;;:::i;7937:405::-;;;;;;;;;;-1:-1:-1;7937:405:0;;;;;:::i;:::-;8165:4;8158:22;8207:31;8201:4;8194:45;8061:11;8253:19;8318:4;8312;8302:21;8296:28;;7937:405;106454:510;;;;;;;;;;-1:-1:-1;106454:510:0;;;;;:::i;:::-;;:::i;49471:724::-;;;;;;:::i;:::-;;:::i;47408:358::-;;;;;;:::i;:::-;;:::i;50832:449::-;;;;;;;;;;-1:-1:-1;50832:449:0;;;;;:::i;:::-;51111:19;51105:4;51098:33;;;50955:14;51145:26;;;;51257:4;51241:21;;51235:28;;50832:449;105367:92;105413:13;105446:5;105439:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105367:92;:::o;6874:544::-;6936:14;7044:2;7038:4;7031:16;-1:-1:-1;;;7068:4:0;7061:38;7166:4;7160;7150:21;7146:2;7142:30;7138:2;7134:39;7211:13;7205:20;7201:2;7197:29;7187:161;;7260:10;7254:4;7247:24;7328:4;7322;7315:18;7187:161;7382:1;7378:21;7372:28;;6874:544;-1:-1:-1;;6874:544:0:o;7722:121::-;7802:33;7811:10;7823:7;7832:2;7802:8;:33::i;:::-;7722:121;;:::o;9595:2944::-;9877:1;10025:16;;;-1:-1:-1;;;10097:8:0;10068:38;10062:4;10055:52;10174:4;10158:21;;10150:30;;10142:39;;10218:20;;-1:-1:-1;;;;;9902:25:0;;;;9947:23;;;;10265:36;;;10142:39;10419:15;;;10408:27;;10398:233;;10561:18;10552:5;10545:13;10542:1;10538:21;10531:49;10611:4;10605;10598:18;10398:233;10737:4;10731;10724:18;10796:13;10793:1;10789:21;10783:28;10760:51;;10948:15;10938:8;10935:29;10928:4;10918:8;10915:18;10912:53;10902:293;;11022:4;11016;11006:21;11000:28;10990:186;;11070:10;11064:4;11057:24;11148:4;11142;11135:18;10990:186;11272:15;11269:55;;;11320:1;11304:13;11301:1;11297:21;11290:32;11269:55;11439:13;;;11418:35;11396:58;;-1:-1:-1;11575:4:0;11569;11559:21;;;11626:22;;-1:-1:-1;;11622:30:0;11598:55;;-1:-1:-1;11748:16:0;;;11803:21;11873:20;;11650:1;11869:28;12051:20;12026:46;;12018:55;;12008:274;;12204:18;12198:2;12191:10;12188:1;12184:18;12177:46;12258:4;12252;12245:18;12008:274;12300:42;;12474:2;12470;12464:4;12437:25;12431:4;12419:10;12414:63;12498:33;9595:2944;;;:::o;48099:630::-;48194:15;47024:9;48212:46;;:15;:46;48194:64;;48430:19;48424:4;48417:33;48481:8;48475:4;48468:22;48538:7;48531:4;48525;48515:21;48508:38;48687:8;48640:45;48637:1;48634;48629:67;48330:381;48099:630::o;12613:201::-;12711:26;12724:4;12730:2;12734;12711:12;:26::i;:::-;37837:14;;12748:58;;;12766:40;12789:4;12795:2;12799;12766:40;;;;;;;;;;;;:22;:40::i;106972:214::-;107028:39;107047:10;107059:7;107028:18;:39::i;:::-;107023:67;;107076:14;;-1:-1:-1;;;107076:14:0;;;;;;;;;;;107023:67;107101:14;107107:7;107101:5;:14::i;:::-;-1:-1:-1;107151:11:0;:16;;-1:-1:-1;;107151:16:0;;;;;;;;;;;;;-1:-1:-1;;107151:16:0;;;;;;106972:214::o;48814:466::-;49020:19;49014:4;49007:33;49067:8;49061:4;49054:22;49120:1;49113:4;49107;49097:21;49090:32;49253:8;49207:44;49204:1;49201;49196:66;48814:466::o;5699:341::-;5757:14;15155:16;;;-1:-1:-1;;;15192:4:0;15185:38;15301:4;15285:21;;15277:30;;15269:39;;15263:46;-1:-1:-1;;;;;15247:64:0;;5884:138;;5934:10;5928:4;5921:24;6002:4;5996;5989:18;5884:138;5699:341;;;:::o;107305:264::-;51678:13;:11;:13::i;:::-;107356:10:::1;:18:::0;;-1:-1:-1;;107356:18:0::1;::::0;;107390:12:::1;::::0;::::1;::::0;107369:5:::1;::::0;107390:12:::1;107431:11;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;107466:9;;::::1;;107457:18:::0;::::1;107453:109;;;107492:9;:18:::0;;-1:-1:-1;;107492:18:0::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;107530:20:::1;::::0;::::1;::::0;-1:-1:-1;;107530:20:0::1;107453:109;107345:224;107305:264::o:0;107875:257::-;51678:13;:11;:13::i;:::-;108005:35:::1;::::0;107955:21:::1;::::0;107938:14:::1;::::0;-1:-1:-1;;;;;108005:16:0;::::1;::::0;107955:21;;107938:14;108005:35;107938:14;108005:35;107955:21;108005:16;:35:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107987:53;;;108056:7;108051:37;;108072:16;;-1:-1:-1::0;;;108072:16:0::1;;;;;;;;;;;108051:37;108104:20;::::0;108117:6;;-1:-1:-1;;;;;108104:20:0;::::1;::::0;::::1;::::0;;;::::1;107927:205;;107875:257:::0;:::o;6190:545::-;6253:14;6417:5;6407:146;;6456:10;6450:4;6443:24;6533:4;6527;6520:18;6407:146;-1:-1:-1;;;6574:4:0;6567:38;6632:5;6626:4;6619:19;6696:20;6688:4;6682;6672:21;6666:28;6662:55;6652:65;;6190:545;;;:::o;108140:143::-;51678:13;:11;:13::i;:::-;108219:9:::1;::::0;-1:-1:-1;;;108219:9:0;::::1;;;108214:25;;108230:9;:7;:9::i;:::-;108250:25;:23;:25::i;:::-;108140:143::o:0;107769:98::-;51678:13;:11;:13::i;:::-;107816:9:::1;:16:::0;;-1:-1:-1;;107816:16:0::1;-1:-1:-1::0;;;107816:16:0::1;::::0;;107848:11:::1;::::0;::::1;::::0;107816:16;;107848:11:::1;107769:98::o:0;107577:184::-;51678:13;:11;:13::i;:::-;107658:9:::1;::::0;-1:-1:-1;;;107658:9:0;::::1;;;107654:30;;;107676:8;;-1:-1:-1::0;;;107676:8:0::1;;;;;;;;;;;107654:30;107695:8;:19;107706:8:::0;107695;:19:::1;:::i;:::-;;107744:8;107730:23;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;107577:184:::0;:::o;105467:96::-;105515:13;105548:7;105541:14;;;;;:::i;8487:741::-;8706:10;8699:18;8692:26;8678:40;;8817:8;8811:4;8804:22;8853:31;8847:4;8840:45;8912:8;8906:4;8899:22;8965:10;8958:4;8952;8942:21;8935:41;9052:10;9046:4;9039:24;9199:8;9195:2;9191:17;9187:2;9183:26;9173:8;9138:33;9132:4;9126;9121:89;8487:741;;:::o;13331:256::-;13482:26;13495:4;13501:2;13505;13482:12;:26::i;:::-;37837:14;;13519:60;;;13537:42;13560:4;13566:2;13570;13574:4;;13537:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;13537:22:0;;-1:-1:-1;;;13537:42:0:i;:::-;13331:256;;;;;:::o;107194:103::-;51678:13;:11;:13::i;:::-;107244:10:::1;:17:::0;;-1:-1:-1;;107244:17:0::1;::::0;::::1;::::0;;107277:12:::1;::::0;::::1;::::0;107244:17;;107277:12:::1;107194:103::o:0;105698:189::-;105763:13;105794:16;105802:7;14587:11;14679:16;;;-1:-1:-1;;;14716:4:0;14709:38;14831:4;14815:21;;14807:30;;14799:39;14793:46;14789:2;14785:55;14778:63;14771:71;;14527:333;105794:16;105789:90;;-1:-1:-1;;105812:9:0;;;;;;;;;-1:-1:-1;105812:9:0;;;105698:189::o;105789:90::-;105844:35;105860:18;:7;:16;:18::i;:::-;105844:8;:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:35;;;;:::i;:::-;105837:42;105698:189;-1:-1:-1;;105698:189:0:o;105571:119::-;105617:13;105650:32;;;;;;;;;;;;;;-1:-1:-1;;;105650:32:0;;;:8;:15;;;;;:::i;:32::-;105643:39;;105571:119;:::o;106454:510::-;51678:13;:11;:13::i;:::-;106561::::1;::::0;::::1;::::0;::::1;::::0;106590:10;;::::1;;;106585:32;;106609:8;;-1:-1:-1::0;;;106609:8:0::1;;;;;;;;;;;106585:32;106657:9;::::0;;;::::1;;;106632:22;106648:6:::0;106632:13;:22:::1;:::i;:::-;:34;;;106628:65;;;106675:18;;-1:-1:-1::0;;;106675:18:0::1;;;;;;;;;;;106628:65;106709:8;106704:147;106723:6;106719:10;;:1;:10;;;106704:147;;;106776:26;106782:2;106786:15;;;;;;106776:26;;:5;:26::i;:::-;106821:3;;106704:147;;;-1:-1:-1::0;;106886:11:0::1;:21:::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;;106922:23:::0;;;;;;;;;::::1;;-1:-1:-1::0;;106922:23:0;;;-1:-1:-1;;106922:23:0;;;;;;;::::1;::::0;;-1:-1:-1;106454:510:0:o;49471:724::-;51678:13;:11;:13::i;:::-;49709:19:::1;49703:4;49696:33;49756:12;49750:4;49743:26;49819:4;49813;49803:21;49927:12;49921:19;49908:11;49905:36;49902:160;;;49974:10;49968:4;49961:24;50042:4;50036;50029:18;49902:160;50141:1;50120:23:::0;;50164::::1;50174:12:::0;50164:9:::1;:23::i;47408:358::-:0;51678:13;:11;:13::i;:::-;47583:8:::1;47579:2;47575:17;47565:153;;47626:10;47620:4;47613:24;47698:4;47692;47685:18;47565:153;47739:19;47749:8;47739:9;:19::i;28304:1472::-:0;28490:1;28486:6;28482:2;28478:15;28538:7;28522:14;28518:28;28507:39;;28586:2;28570:14;28566:23;28560:29;;28661:2;28655:4;28648:16;28720:2;-1:-1:-1;;;28691:32:0;28685:4;28678:46;28791:4;28785;28775:21;28771:2;28767:30;28763:2;28759:39;28851:13;28845:20;28829:14;28825:41;28812:54;;28942:5;28932:137;;28981:10;28975:4;28968:24;29049:4;29043;29036:18;28932:137;29255:5;29251:2;29248:13;29243:2;29236:10;29233:29;29223:286;;29296:5;29290:4;29283:19;29352:4;29346;29336:21;29330:28;29320:174;;29396:10;29390:4;29383:24;29470:4;29464;29457:18;29320:174;29605:1;29601:21;29594:38;;;29755:2;29624:7;29739:5;29712:25;29706:4;29694:10;29689:69;;28304:1472;;;:::o;38064:1400::-;38307:4;38301:11;38358:10;38392:24;38389:1;38382:35;38452:8;38445:4;38442:1;38438:12;38431:30;38561:4;38557:2;38553:13;38549:2;38545:22;38538:4;38535:1;38531:12;38524:44;38603:2;38596:4;38593:1;38589:12;38582:24;38641:4;38634;38631:1;38627:12;38620:26;38675:4;38669:11;38715:1;38708:4;38705:1;38701:12;38694:23;38734:1;38731:71;;;38797:1;38790:4;38787:1;38783:12;38780:1;38773:4;38767;38763:15;38760:1;38753:5;38742:57;38738:62;38731:71;38920:4;38917:1;38910:4;38907:1;38903:12;38896:4;38893:1;38889:12;38886:1;38882:2;38875:5;38870:55;38860:319;;38949:16;38946:218;;;39079:16;39073:4;39070:1;39055:41;39128:16;39125:1;39118:27;38946:218;38860:319;39277:24;39272:3;39268:34;39264:1;39258:8;39255:48;39245:201;;39337:10;39331:4;39324:24;39426:4;39420;39413:18;39245:201;;;38064:1400;;;;:::o;26116:1190::-;26240:11;26494:16;;;-1:-1:-1;;;;;26414:25:0;;;-1:-1:-1;;;26537:37:0;;26531:4;26524:51;26642:4;26626:21;;;26618:30;;26610:39;;26692:20;;26414:25;;26347:1;;26676:38;;26780:137;;26829:10;26823:4;26816:24;26897:4;26891;26884:18;26780:137;27004:5;26995:7;26992:18;26982:306;;27044:5;27038:4;27031:19;27172:4;27166;27156:21;27150:28;27140:133;;27238:13;27235:1;27231:21;27225:28;27216:7;27213:41;27203:51;;27140:133;26982:306;;26116:1190;;;;:::o;23102:84::-;23157:21;23171:1;23175:2;23157:5;:21::i;46329:364::-;-1:-1:-1;;46539:18:0;46529:8;46526:32;46516:159;;46592:10;46586:4;46579:24;46655:4;46649;46642:18;47834:102;51678:13;:11;:13::i;:::-;47907:21:::1;47925:1;47907:9;:21::i;53039:1676::-:0;53095:17;53547:4;53540;53534:11;53530:22;53523:29;;53648:4;53643:3;53639:14;53633:4;53626:28;53731:1;53726:3;53719:14;53835:3;53867:1;53863:6;54079:5;54061:410;54118:11;;;;54302:2;54316;54306:13;;54298:22;54118:11;54285:36;54410:2;54400:13;;54431:25;54061:410;54431:25;-1:-1:-1;;54501:13:0;;;-1:-1:-1;;54616:14:0;;;54678:19;;;54616:14;53039:1676;-1:-1:-1;53039:1676:0:o;89220:1399::-;89474:4;89468:11;89508:8;;-1:-1:-1;;89435:9:0;89618:4;89605:18;;89601:26;;89586:214;89683:9;;;89677:16;89661:14;;;89654:40;89717:9;;89763:22;89586:214;89763:22;89590:39;89835:1;89829:8;89877:7;89869:6;89865:20;89994:1;89987:4;89978:7;89974:18;89970:26;89955:214;90052:9;;;90046:16;90030:14;;;90023:40;90086:9;;90132:22;89955:214;90132:22;-1:-1:-1;;90362:1:0;90202:21;;90249:35;;;90265:4;90249:35;;90349:15;;;;90413:27;;90581:15;;90577:23;90571:4;90564:37;90257:6;89220:1399;-1:-1:-1;;89220:1399:0:o;18651:1688::-;18900:2;18896;18892:11;18888:2;18884:20;18878:26;;18972:2;18966:4;18959:16;-1:-1:-1;;;18996:4:0;18989:38;19094:4;19088;19078:21;19074:2;19070:30;19066:2;19062:39;19144:13;19138:20;19235:15;19231:2;19227:24;19224:149;;;19284:10;19278:4;19271:24;19353:4;19347;19340:18;19224:149;19448:23;;19426:46;;19564:4;19557:16;;;19626:4;19620;19610:21;19678:18;;19698:1;19674:26;19852:20;19829:44;;19821:53;;19811:272;;20005:18;19999:2;19992:10;19989:1;19985:18;19978:46;20059:4;20053;20046:18;19811:272;20101:38;;20268:2;20264;20261:1;20234:25;20261:1;20216:10;20211:60;7722:121;;:::o;45155:1113::-;-1:-1:-1;;46122:16:0;;-1:-1:-1;;;;;45968:26:0;;;;;;46082:38;46079:1;;46071:78;46208:27;45155:1113::o;23486:2172::-;23553:13;23569:11;23577:2;23569:7;:11::i;:::-;23553:27;;-1:-1:-1;23842:4:0;23835:16;;;-1:-1:-1;;;;;23760:20:0;;;-1:-1:-1;;;23878:32:0;;23872:4;23865:46;23978:4;23962:21;;;23954:30;;23946:39;;24022:20;;23760;;24147:33;;;;24246:137;;24295:10;24289:4;24282:24;24363:4;24357;24350:18;24246:137;24480:5;24474:4;24467:19;24540:13;24537:1;24533:21;24527:28;24775:15;24771:2;24768:23;24760:5;24756:2;24753:13;24750:42;24745:2;24738:10;24735:58;24725:298;;24850:4;24844;24834:21;24828:28;24818:186;;24898:10;24892:4;24885:24;24976:4;24970;24963:18;24818:186;25100:15;25097:55;;;25148:1;25132:13;25129:1;25125:21;25118:32;25097:55;-1:-1:-1;25236:27:0;;25214:50;;25382:4;25376;25366:21;25429:18;;-1:-1:-1;;25425:26:0;25405:47;;25584:2;-1:-1:-1;25257:5:0;25547:25;-1:-1:-1;25529:10:0;25524:63;9595:2944;;;:::o;14:286:1:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:1;;209:43;;199:71;;266:1;263;256:12;199:71;289:5;14:286;-1:-1:-1;;;14:286:1:o;497:250::-;582:1;592:113;606:6;603:1;600:13;592:113;;;682:11;;;676:18;663:11;;;656:39;628:2;621:10;592:113;;;-1:-1:-1;;739:1:1;721:16;;714:27;497:250::o;752:396::-;901:2;890:9;883:21;864:4;933:6;927:13;976:6;971:2;960:9;956:18;949:34;992:79;1064:6;1059:2;1048:9;1044:18;1039:2;1031:6;1027:15;992:79;:::i;:::-;1132:2;1111:15;-1:-1:-1;;1107:29:1;1092:45;;;;1139:2;1088:54;;752:396;-1:-1:-1;;752:396:1:o;1153:180::-;1212:6;1265:2;1253:9;1244:7;1240:23;1236:32;1233:52;;;1281:1;1278;1271:12;1233:52;-1:-1:-1;1304:23:1;;1153:180;-1:-1:-1;1153:180:1:o;1546:173::-;1614:20;;-1:-1:-1;;;;;1663:31:1;;1653:42;;1643:70;;1709:1;1706;1699:12;1724:254;1792:6;1800;1853:2;1841:9;1832:7;1828:23;1824:32;1821:52;;;1869:1;1866;1859:12;1821:52;1892:29;1911:9;1892:29;:::i;:::-;1882:39;1968:2;1953:18;;;;1940:32;;-1:-1:-1;;;1724:254:1:o;2176:328::-;2253:6;2261;2269;2322:2;2310:9;2301:7;2297:23;2293:32;2290:52;;;2338:1;2335;2328:12;2290:52;2361:29;2380:9;2361:29;:::i;:::-;2351:39;;2409:38;2443:2;2432:9;2428:18;2409:38;:::i;:::-;2399:48;;2494:2;2483:9;2479:18;2466:32;2456:42;;2176:328;;;;;:::o;2509:186::-;2568:6;2621:2;2609:9;2600:7;2596:23;2592:32;2589:52;;;2637:1;2634;2627:12;2589:52;2660:29;2679:9;2660:29;:::i;2882:127::-;2943:10;2938:3;2934:20;2931:1;2924:31;2974:4;2971:1;2964:15;2998:4;2995:1;2988:15;3014:922;3083:6;3136:2;3124:9;3115:7;3111:23;3107:32;3104:52;;;3152:1;3149;3142:12;3104:52;3192:9;3179:23;3221:18;3262:2;3254:6;3251:14;3248:34;;;3278:1;3275;3268:12;3248:34;3316:6;3305:9;3301:22;3291:32;;3361:7;3354:4;3350:2;3346:13;3342:27;3332:55;;3383:1;3380;3373:12;3332:55;3419:2;3406:16;3441:2;3437;3434:10;3431:36;;;3447:18;;:::i;:::-;3522:2;3516:9;3490:2;3576:13;;-1:-1:-1;;3572:22:1;;;3596:2;3568:31;3564:40;3552:53;;;3620:18;;;3640:22;;;3617:46;3614:72;;;3666:18;;:::i;:::-;3706:10;3702:2;3695:22;3741:2;3733:6;3726:18;3781:7;3776:2;3771;3767;3763:11;3759:20;3756:33;3753:53;;;3802:1;3799;3792:12;3753:53;3858:2;3853;3849;3845:11;3840:2;3832:6;3828:15;3815:46;3903:1;3881:15;;;3898:2;3877:24;3870:35;;;;-1:-1:-1;3885:6:1;3014:922;-1:-1:-1;;;;;3014:922:1:o;4146:347::-;4211:6;4219;4272:2;4260:9;4251:7;4247:23;4243:32;4240:52;;;4288:1;4285;4278:12;4240:52;4311:29;4330:9;4311:29;:::i;:::-;4301:39;;4390:2;4379:9;4375:18;4362:32;4437:5;4430:13;4423:21;4416:5;4413:32;4403:60;;4459:1;4456;4449:12;4403:60;4482:5;4472:15;;;4146:347;;;;;:::o;4498:808::-;4595:6;4603;4611;4619;4627;4680:3;4668:9;4659:7;4655:23;4651:33;4648:53;;;4697:1;4694;4687:12;4648:53;4720:29;4739:9;4720:29;:::i;:::-;4710:39;;4768:38;4802:2;4791:9;4787:18;4768:38;:::i;:::-;4758:48;;4853:2;4842:9;4838:18;4825:32;4815:42;;4908:2;4897:9;4893:18;4880:32;4931:18;4972:2;4964:6;4961:14;4958:34;;;4988:1;4985;4978:12;4958:34;5026:6;5015:9;5011:22;5001:32;;5071:7;5064:4;5060:2;5056:13;5052:27;5042:55;;5093:1;5090;5083:12;5042:55;5133:2;5120:16;5159:2;5151:6;5148:14;5145:34;;;5175:1;5172;5165:12;5145:34;5220:7;5215:2;5206:6;5202:2;5198:15;5194:24;5191:37;5188:57;;;5241:1;5238;5231:12;5188:57;4498:808;;;;-1:-1:-1;4498:808:1;;-1:-1:-1;5272:2:1;5264:11;;5294:6;4498:808;-1:-1:-1;;;4498:808:1:o;5311:260::-;5379:6;5387;5440:2;5428:9;5419:7;5415:23;5411:32;5408:52;;;5456:1;5453;5446:12;5408:52;5479:29;5498:9;5479:29;:::i;:::-;5469:39;;5527:38;5561:2;5550:9;5546:18;5527:38;:::i;:::-;5517:48;;5311:260;;;;;:::o;5576:346::-;5643:6;5651;5704:2;5692:9;5683:7;5679:23;5675:32;5672:52;;;5720:1;5717;5710:12;5672:52;5743:29;5762:9;5743:29;:::i;:::-;5733:39;;5822:2;5811:9;5807:18;5794:32;5866:6;5859:5;5855:18;5848:5;5845:29;5835:57;;5888:1;5885;5878:12;5927:380;6006:1;6002:12;;;;6049;;;6070:61;;6124:4;6116:6;6112:17;6102:27;;6070:61;6177:2;6169:6;6166:14;6146:18;6143:38;6140:161;;6223:10;6218:3;6214:20;6211:1;6204:31;6258:4;6255:1;6248:15;6286:4;6283:1;6276:15;6140:161;;5927:380;;;:::o;6648:518::-;6750:2;6745:3;6742:11;6739:421;;;6786:5;6783:1;6776:16;6830:4;6827:1;6817:18;6900:2;6888:10;6884:19;6881:1;6877:27;6871:4;6867:38;6936:4;6924:10;6921:20;6918:47;;;-1:-1:-1;6959:4:1;6918:47;7014:2;7009:3;7005:12;7002:1;6998:20;6992:4;6988:31;6978:41;;7069:81;7087:2;7080:5;7077:13;7069:81;;;7146:1;7132:16;;7113:1;7102:13;7069:81;;7342:1345;7468:3;7462:10;7495:18;7487:6;7484:30;7481:56;;;7517:18;;:::i;:::-;7546:97;7636:6;7596:38;7628:4;7622:11;7596:38;:::i;:::-;7590:4;7546:97;:::i;:::-;7698:4;;7755:2;7744:14;;7772:1;7767:663;;;;8474:1;8491:6;8488:89;;;-1:-1:-1;8543:19:1;;;8537:26;8488:89;-1:-1:-1;;7299:1:1;7295:11;;;7291:24;7287:29;7277:40;7323:1;7319:11;;;7274:57;8590:81;;7737:944;;7767:663;6595:1;6588:14;;;6632:4;6619:18;;-1:-1:-1;;7803:20:1;;;7921:236;7935:7;7932:1;7929:14;7921:236;;;8024:19;;;8018:26;8003:42;;8116:27;;;;8084:1;8072:14;;;;7951:19;;7921:236;;;7925:3;8185:6;8176:7;8173:19;8170:201;;;8246:19;;;8240:26;-1:-1:-1;;8329:1:1;8325:14;;;8341:3;8321:24;8317:37;8313:42;8298:58;8283:74;;8170:201;-1:-1:-1;;;;;8417:1:1;8401:14;;;8397:22;8384:36;;-1:-1:-1;7342:1345:1:o;8692:289::-;8823:3;8861:6;8855:13;8877:66;8936:6;8931:3;8924:4;8916:6;8912:17;8877:66;:::i;:::-;8959:16;;;;;8692:289;-1:-1:-1;;8692:289:1:o;8986:265::-;9053:6;9079:10;;;9091;;;9075:27;;9114:11;;;9111:134;;;9167:10;9162:3;9158:20;9155:1;9148:31;9202:4;9199:1;9192:15;9230:4;9227:1;9220:15;9111:134;;8986:265;;;;:::o

Swarm Source

ipfs://500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de
Loading...
Loading
Loading...
Loading
[ 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.