ETH Price: $2,148.72 (+0.71%)

Transaction Decoder

Block:
21744010 at Jan-31-2025 10:47:35 AM +UTC
Transaction Fee:
0.000083439741710214 ETH $0.18
Gas Used:
43,794 Gas / 1.905277931 Gwei

Emitted Events:

289 0xe2a2811e8f62cb9a8520614e082d59728af26ddd.0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62( 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62, 0x0000000000000000000000006bd4f76e2c0453bfc6f7177542808e22a4ee323f, 0x0000000000000000000000006bd4f76e2c0453bfc6f7177542808e22a4ee323f, 0x00000000000000000000000019e5ecb3f15197e7a72996259c2245919c9725dd, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
5.813192856700517211 Eth5.813214753700517211 Eth0.000021897
0x6bD4f76e...2A4Ee323F
0.774700162628014197 Eth
Nonce: 867
0.774616722886303983 Eth
Nonce: 868
0.000083439741710214
0xE2a2811E...28aF26ddD

Execution Trace

0xe2a2811e8f62cb9a8520614e082d59728af26ddd.f242432a( )
  • ERC1155SeaDropCloneable.safeTransferFrom( from=0x6bD4f76e2c0453bFC6F7177542808E22A4Ee323F, to=0x19E5ECB3F15197E7A72996259C2245919C9725dD, id=1, amount=1, data=0x )
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import {
        ERC1155SeaDropContractOffererCloneable
    } from "./ERC1155SeaDropContractOffererCloneable.sol";
    /**
     * @title  ERC1155SeaDropCloneable
     * @author James Wenzel (emo.eth)
     * @author Ryan Ghods (ralxz.eth)
     * @author Stephan Min (stephanm.eth)
     * @author Michael Cohen (notmichael.eth)
     * @custom:contributor Limit Break (@limitbreak)
     * @notice A cloneable ERC1155 token contract that can mint as a
     *         Seaport contract offerer.
     *         Implements Limit Break's Creator Token Standards transfer
     *         validation for royalty enforcement.
     */
    contract ERC1155SeaDropCloneable is ERC1155SeaDropContractOffererCloneable {
        /**
         * @notice Initialize the token contract.
         *
         * @param allowedConfigurer The address of the contract allowed to
         *                          implementation code. Also contains SeaDrop
         *                          implementation code.
         * @param allowedSeaport    The address of the Seaport contract allowed to
         *                          interact.
         * @param name_             The name of the token.
         * @param symbol_           The symbol of the token.
         */
        function initialize(
            address allowedConfigurer,
            address allowedSeaport,
            string memory name_,
            string memory symbol_,
            address initialOwner
        ) public initializer {
            // Initialize ownership.
            _initializeOwner(initialOwner);
            // Initialize ERC1155SeaDropContractOffererCloneable.
            __ERC1155SeaDropContractOffererCloneable_init(
                allowedConfigurer,
                allowedSeaport,
                name_,
                symbol_
            );
        }
        /**
         * @notice Burns a token, restricted to the owner or approved operator,
         *         and must have sufficient balance.
         *
         * @param from   The address to burn from.
         * @param id     The token id to burn.
         * @param amount The amount to burn.
         */
        function burn(address from, uint256 id, uint256 amount) external {
            // Burn the token.
            _burn(msg.sender, from, id, amount);
        }
        /**
         * @notice Burns a batch of tokens, restricted to the owner or
         *         approved operator, and must have sufficient balance.
         *
         * @param from    The address to burn from.
         * @param ids     The token ids to burn.
         * @param amounts The amounts to burn per token id.
         */
        function batchBurn(
            address from,
            uint256[] calldata ids,
            uint256[] calldata amounts
        ) external {
            // Burn the tokens.
            _batchBurn(msg.sender, from, ids, amounts);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { IERC1155SeaDrop } from "../interfaces/IERC1155SeaDrop.sol";
    import { ISeaDropToken } from "../interfaces/ISeaDropToken.sol";
    import {
        ERC1155ContractMetadataCloneable
    } from "./ERC1155ContractMetadataCloneable.sol";
    import {
        ERC1155SeaDropContractOffererStorage
    } from "../lib/ERC1155SeaDropContractOffererStorage.sol";
    import {
        ERC1155SeaDropErrorsAndEvents
    } from "../lib/ERC1155SeaDropErrorsAndEvents.sol";
    import { PublicDrop } from "../lib//ERC1155SeaDropStructs.sol";
    import { AllowListData } from "../lib/SeaDropStructs.sol";
    import {
        ERC1155ConduitPreapproved
    } from "../lib/ERC1155ConduitPreapproved.sol";
    import { ERC1155 } from "solady/src/tokens/ERC1155.sol";
    import { SpentItem } from "seaport-types/src/lib/ConsiderationStructs.sol";
    import {
        ContractOffererInterface
    } from "seaport-types/src/interfaces/ContractOffererInterface.sol";
    import {
        IERC165
    } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
    /**
     * @title  ERC1155SeaDropContractOffererCloneable
     * @author James Wenzel (emo.eth)
     * @author Ryan Ghods (ralxz.eth)
     * @author Stephan Min (stephanm.eth)
     * @author Michael Cohen (notmichael.eth)
     * @notice A cloneable ERC1155 token contract that can mint as a
     *         Seaport contract offerer.
     */
    contract ERC1155SeaDropContractOffererCloneable is
        ERC1155ContractMetadataCloneable,
        ERC1155SeaDropErrorsAndEvents
    {
        using ERC1155SeaDropContractOffererStorage for ERC1155SeaDropContractOffererStorage.Layout;
        /**
         * @notice Initialize the token contract.
         *
         * @param allowedConfigurer The address of the contract allowed to
         *                          configure parameters. Also contains SeaDrop
         *                          implementation code.
         * @param allowedSeaport    The address of the Seaport contract allowed to
         *                          interact.
         * @param name_             The name of the token.
         * @param symbol_           The symbol of the token.
         */
        function __ERC1155SeaDropContractOffererCloneable_init(
            address allowedConfigurer,
            address allowedSeaport,
            string memory name_,
            string memory symbol_
        ) internal onlyInitializing {
            // Set the allowed Seaport to interact with this contract.
            if (allowedSeaport == address(0)) {
                revert AllowedSeaportCannotBeZeroAddress();
            }
            ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[
                allowedSeaport
            ] = true;
            // Set the allowed Seaport enumeration.
            address[] memory enumeratedAllowedSeaport = new address[](1);
            enumeratedAllowedSeaport[0] = allowedSeaport;
            ERC1155SeaDropContractOffererStorage
                .layout()
                ._enumeratedAllowedSeaport = enumeratedAllowedSeaport;
            // Emit an event noting the contract deployment.
            emit SeaDropTokenDeployed(SEADROP_TOKEN_TYPE.ERC1155_CLONE);
            // Initialize ERC1155ContractMetadataCloneable.
            __ERC1155ContractMetadataCloneable_init(
                allowedConfigurer,
                name_,
                symbol_
            );
        }
        /**
         * @notice The fallback function is used as a dispatcher for SeaDrop
         *         methods.
         */
        fallback(bytes calldata) external returns (bytes memory output) {
            // Get the function selector.
            bytes4 selector = msg.sig;
            // Get the rest of the msg data after the selector.
            bytes calldata data = msg.data[4:];
            // Determine if we should forward the call to the implementation
            // contract with SeaDrop logic.
            bool callSeaDropImplementation = selector ==
                ISeaDropToken.updateAllowedSeaport.selector ||
                selector == ISeaDropToken.updateDropURI.selector ||
                selector == ISeaDropToken.updateAllowList.selector ||
                selector == ISeaDropToken.updateCreatorPayouts.selector ||
                selector == ISeaDropToken.updatePayer.selector ||
                selector == ISeaDropToken.updateAllowedFeeRecipient.selector ||
                selector == ISeaDropToken.updateSigner.selector ||
                selector == IERC1155SeaDrop.updatePublicDrop.selector ||
                selector == ContractOffererInterface.previewOrder.selector ||
                selector == ContractOffererInterface.generateOrder.selector ||
                selector == ContractOffererInterface.getSeaportMetadata.selector ||
                selector == IERC1155SeaDrop.getPublicDrop.selector ||
                selector == IERC1155SeaDrop.getPublicDropIndexes.selector ||
                selector == ISeaDropToken.getAllowedSeaport.selector ||
                selector == ISeaDropToken.getCreatorPayouts.selector ||
                selector == ISeaDropToken.getAllowListMerkleRoot.selector ||
                selector == ISeaDropToken.getAllowedFeeRecipients.selector ||
                selector == ISeaDropToken.getSigners.selector ||
                selector == ISeaDropToken.getDigestIsUsed.selector ||
                selector == ISeaDropToken.getPayers.selector;
            // Determine if we should require only the owner or configurer calling.
            bool requireOnlyOwnerOrConfigurer = selector ==
                ISeaDropToken.updateAllowedSeaport.selector ||
                selector == ISeaDropToken.updateDropURI.selector ||
                selector == ISeaDropToken.updateAllowList.selector ||
                selector == ISeaDropToken.updateCreatorPayouts.selector ||
                selector == ISeaDropToken.updatePayer.selector ||
                selector == ISeaDropToken.updateAllowedFeeRecipient.selector ||
                selector == IERC1155SeaDrop.updatePublicDrop.selector;
            if (callSeaDropImplementation) {
                // For update calls, ensure the sender is only the owner
                // or configurer contract.
                if (requireOnlyOwnerOrConfigurer) {
                    _onlyOwnerOrConfigurer();
                } else if (selector == ISeaDropToken.updateSigner.selector) {
                    // For updateSigner, a signer can disallow themselves.
                    // Get the signer parameter.
                    address signer = address(bytes20(data[12:32]));
                    // If the signer is not allowed, ensure sender is only owner
                    // or configurer.
                    if (
                        msg.sender != signer ||
                        (msg.sender == signer &&
                            !ERC1155SeaDropContractOffererStorage
                                .layout()
                                ._allowedSigners[signer])
                    ) {
                        _onlyOwnerOrConfigurer();
                    }
                }
                // Forward the call to the implementation contract.
                (bool success, bytes memory returnedData) = _CONFIGURER
                    .delegatecall(msg.data);
                // Require that the call was successful.
                if (!success) {
                    // Bubble up the revert reason.
                    assembly {
                        revert(add(32, returnedData), mload(returnedData))
                    }
                }
                // If the call was to generateOrder, mint the tokens.
                if (selector == ContractOffererInterface.generateOrder.selector) {
                    _mintOrder(data);
                }
                // Return the data from the delegate call.
                return returnedData;
            } else if (selector == IERC1155SeaDrop.getMintStats.selector) {
                // Get the minter and token id.
                (address minter, uint256 tokenId) = abi.decode(
                    data,
                    (address, uint256)
                );
                // Get the mint stats.
                (
                    uint256 minterNumMinted,
                    uint256 minterNumMintedForTokenId,
                    uint256 totalMintedForTokenId,
                    uint256 maxSupply
                ) = _getMintStats(minter, tokenId);
                // Encode the return data.
                return
                    abi.encode(
                        minterNumMinted,
                        minterNumMintedForTokenId,
                        totalMintedForTokenId,
                        maxSupply
                    );
            } else if (selector == ContractOffererInterface.ratifyOrder.selector) {
                // This function is a no-op, nothing additional needs to happen here.
                // Utilize assembly to efficiently return the ratifyOrder magic value.
                assembly {
                    mstore(0, 0xf4dd92ce)
                    return(0x1c, 32)
                }
            } else if (selector == ISeaDropToken.configurer.selector) {
                // Return the configurer contract.
                return abi.encode(_CONFIGURER);
            } else if (selector == IERC1155SeaDrop.multiConfigureMint.selector) {
                // Ensure only the owner or configurer can call this function.
                _onlyOwnerOrConfigurer();
                // Mint the tokens.
                _multiConfigureMint(data);
            } else {
                // Revert if the function selector is not supported.
                revert UnsupportedFunctionSelector(selector);
            }
        }
        /**
         * @notice Returns a set of mint stats for the address.
         *         This assists in enforcing maxSupply, maxTotalMintableByWallet,
         *         and maxTokenSupplyForStage checks.
         *
         * @dev    NOTE: Implementing contracts should always update these numbers
         *         before transferring any tokens with _safeMint() to mitigate
         *         consequences of malicious onERC1155Received() hooks.
         *
         * @param minter  The minter address.
         * @param tokenId The token id to return the stats for.
         */
        function _getMintStats(
            address minter,
            uint256 tokenId
        )
            internal
            view
            returns (
                uint256 minterNumMinted,
                uint256 minterNumMintedForTokenId,
                uint256 totalMintedForTokenId,
                uint256 maxSupply
            )
        {
            // Put the token supply on the stack.
            TokenSupply storage tokenSupply = _tokenSupply[tokenId];
            // Assign the return values.
            totalMintedForTokenId = tokenSupply.totalMinted;
            maxSupply = tokenSupply.maxSupply;
            minterNumMinted = _totalMintedByUser[minter];
            minterNumMintedForTokenId = _totalMintedByUserPerToken[minter][tokenId];
        }
        /**
         * @dev Handle ERC-1155 safeTransferFrom. If "from" is this contract,
         *      the sender can only be Seaport or the conduit.
         *
         * @param from   The address to transfer from.
         * @param to     The address to transfer to.
         * @param id     The token id to transfer.
         * @param amount The amount of tokens to transfer.
         * @param data   The data to pass to the onERC1155Received hook.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes calldata data
        ) public virtual override {
            if (from == address(this)) {
                // Only Seaport or the conduit can use this function
                // when "from" is this contract.
                if (
                    msg.sender != _CONDUIT &&
                    !ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[
                        msg.sender
                    ]
                ) {
                    revert InvalidCallerOnlyAllowedSeaport(msg.sender);
                }
                return;
            }
            ERC1155._safeTransfer(_by(), from, to, id, amount, data);
        }
        /**
         * @notice Returns whether the interface is supported.
         *
         * @param interfaceId The interface id to check against.
         */
        function supportsInterface(
            bytes4 interfaceId
        )
            public
            view
            virtual
            override(ERC1155ContractMetadataCloneable)
            returns (bool)
        {
            return
                interfaceId == type(IERC1155SeaDrop).interfaceId ||
                interfaceId == type(ContractOffererInterface).interfaceId ||
                interfaceId == 0x2e778efc || // SIP-5 (getSeaportMetadata)
                // ERC1155ContractMetadata returns supportsInterface true for
                //     IERC1155ContractMetadata, ERC-4906, ERC-2981
                // ERC1155A returns supportsInterface true for
                //     ERC165, ERC1155, ERC1155MetadataURI
                ERC1155ContractMetadataCloneable.supportsInterface(interfaceId);
        }
        /**
         * @dev Internal function to mint tokens during a generateOrder call
         *      from Seaport.
         *
         * @param data The original transaction calldata, without the selector.
         */
        function _mintOrder(bytes calldata data) internal {
            // Decode fulfiller, minimumReceived, and context from calldata.
            (
                address fulfiller,
                SpentItem[] memory minimumReceived,
                ,
                bytes memory context
            ) = abi.decode(data, (address, SpentItem[], SpentItem[], bytes));
            // Assign the minter from context[22:42]. We validate context has the
            // correct minimum length in the implementation's `_decodeOrder`.
            address minter;
            assembly {
                minter := shr(96, mload(add(add(context, 0x20), 22)))
            }
            // If the minter is the zero address, set it to the fulfiller.
            if (minter == address(0)) {
                minter = fulfiller;
            }
            // Set the token ids and quantities.
            uint256 minimumReceivedLength = minimumReceived.length;
            uint256[] memory tokenIds = new uint256[](minimumReceivedLength);
            uint256[] memory quantities = new uint256[](minimumReceivedLength);
            for (uint256 i = 0; i < minimumReceivedLength; ) {
                tokenIds[i] = minimumReceived[i].identifier;
                quantities[i] = minimumReceived[i].amount;
                unchecked {
                    ++i;
                }
            }
            // Mint the tokens.
            _batchMint(minter, tokenIds, quantities, "");
        }
        /**
         * @dev Internal function to mint tokens during a multiConfigureMint call
         *      from the configurer contract.
         *
         * @param data The original transaction calldata, without the selector.
         */
        function _multiConfigureMint(bytes calldata data) internal {
            // Decode the calldata.
            (
                address recipient,
                uint256[] memory tokenIds,
                uint256[] memory amounts
            ) = abi.decode(data, (address, uint256[], uint256[]));
            _batchMint(recipient, tokenIds, amounts, "");
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { ISeaDropToken } from "./ISeaDropToken.sol";
    import { PublicDrop } from "../lib/ERC1155SeaDropStructs.sol";
    /**
     * @dev A helper interface to get and set parameters for ERC1155SeaDrop.
     *      The token does not expose these methods as part of its external
     *      interface to optimize contract size, but does implement them.
     */
    interface IERC1155SeaDrop is ISeaDropToken {
        /**
         * @notice Update the SeaDrop public drop parameters at a given index.
         *
         * @param publicDrop The new public drop parameters.
         * @param index      The public drop index.
         */
        function updatePublicDrop(
            PublicDrop calldata publicDrop,
            uint256 index
        ) external;
        /**
         * @notice Returns the public drop stage parameters at a given index.
         *
         * @param index The index of the public drop stage.
         */
        function getPublicDrop(
            uint256 index
        ) external view returns (PublicDrop memory);
        /**
         * @notice Returns the public drop indexes.
         */
        function getPublicDropIndexes() external view returns (uint256[] memory);
        /**
         * @notice Returns a set of mint stats for the address.
         *         This assists SeaDrop in enforcing maxSupply,
         *         maxTotalMintableByWallet, maxTotalMintableByWalletPerToken,
         *         and maxTokenSupplyForStage checks.
         *
         * @dev    NOTE: Implementing contracts should always update these numbers
         *         before transferring any tokens with _safeMint() to mitigate
         *         consequences of malicious onERC1155Received() hooks.
         *
         * @param minter  The minter address.
         * @param tokenId The token id to return stats for.
         */
        function getMintStats(
            address minter,
            uint256 tokenId
        )
            external
            view
            returns (
                uint256 minterNumMinted,
                uint256 minterNumMintedForTokenId,
                uint256 totalMintedForTokenId,
                uint256 maxSupply
            );
        /**
         * @notice This function is only allowed to be called by the configurer
         *         contract as a way to batch mints and configuration in one tx.
         *
         * @param recipient The address to receive the mints.
         * @param tokenIds  The tokenIds to mint.
         * @param amounts   The amounts to mint.
         */
        function multiConfigureMint(
            address recipient,
            uint256[] calldata tokenIds,
            uint256[] calldata amounts
        ) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import {
        ISeaDropTokenContractMetadata
    } from "./ISeaDropTokenContractMetadata.sol";
    import { AllowListData, CreatorPayout } from "../lib/SeaDropStructs.sol";
    /**
     * @dev A helper base interface for IERC721SeaDrop and IERC1155SeaDrop.
     *      The token does not expose these methods as part of its external
     *      interface to optimize contract size, but does implement them.
     */
    interface ISeaDropToken is ISeaDropTokenContractMetadata {
        /**
         * @notice Update the SeaDrop allowed Seaport contracts privileged to mint.
         *         Only the owner can use this function.
         *
         * @param allowedSeaport The allowed Seaport addresses.
         */
        function updateAllowedSeaport(address[] calldata allowedSeaport) external;
        /**
         * @notice Update the SeaDrop allowed fee recipient.
         *         Only the owner can use this function.
         *
         * @param feeRecipient The new fee recipient.
         * @param allowed      Whether the fee recipient is allowed.
         */
        function updateAllowedFeeRecipient(
            address feeRecipient,
            bool allowed
        ) external;
        /**
         * @notice Update the SeaDrop creator payout addresses.
         *         The total basis points must add up to exactly 10_000.
         *         Only the owner can use this function.
         *
         * @param creatorPayouts The new creator payouts.
         */
        function updateCreatorPayouts(
            CreatorPayout[] calldata creatorPayouts
        ) external;
        /**
         * @notice Update the SeaDrop drop URI.
         *         Only the owner can use this function.
         *
         * @param dropURI The new drop URI.
         */
        function updateDropURI(string calldata dropURI) external;
        /**
         * @notice Update the SeaDrop allow list data.
         *         Only the owner can use this function.
         *
         * @param allowListData The new allow list data.
         */
        function updateAllowList(AllowListData calldata allowListData) external;
        /**
         * @notice Update the SeaDrop allowed payers.
         *         Only the owner can use this function.
         *
         * @param payer   The payer to update.
         * @param allowed Whether the payer is allowed.
         */
        function updatePayer(address payer, bool allowed) external;
        /**
         * @notice Update the SeaDrop allowed signer.
         *         Only the owner can use this function.
         *         An allowed signer can also disallow themselves.
         *
         * @param signer  The signer to update.
         * @param allowed Whether the signer is allowed.
         */
        function updateSigner(address signer, bool allowed) external;
        /**
         * @notice Get the SeaDrop allowed Seaport contracts privileged to mint.
         */
        function getAllowedSeaport() external view returns (address[] memory);
        /**
         * @notice Returns the SeaDrop creator payouts.
         */
        function getCreatorPayouts() external view returns (CreatorPayout[] memory);
        /**
         * @notice Returns the SeaDrop allow list merkle root.
         */
        function getAllowListMerkleRoot() external view returns (bytes32);
        /**
         * @notice Returns the SeaDrop allowed fee recipients.
         */
        function getAllowedFeeRecipients() external view returns (address[] memory);
        /**
         * @notice Returns the SeaDrop allowed signers.
         */
        function getSigners() external view returns (address[] memory);
        /**
         * @notice Returns if the signed digest has been used.
         *
         * @param digest The digest hash.
         */
        function getDigestIsUsed(bytes32 digest) external view returns (bool);
        /**
         * @notice Returns the SeaDrop allowed payers.
         */
        function getPayers() external view returns (address[] memory);
        /**
         * @notice Returns the configurer contract.
         */
        function configurer() external view returns (address);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import {
        IERC1155ContractMetadata
    } from "../interfaces/IERC1155ContractMetadata.sol";
    import {
        ERC1155ConduitPreapproved
    } from "../lib/ERC1155ConduitPreapproved.sol";
    import {
        ICreatorToken,
        ILegacyCreatorToken
    } from "../interfaces/ICreatorToken.sol";
    import { ITransferValidator1155 } from "../interfaces/ITransferValidator.sol";
    import { TokenTransferValidator } from "../lib/TokenTransferValidator.sol";
    import { ERC1155 } from "solady/src/tokens/ERC1155.sol";
    import { ERC2981 } from "solady/src/tokens/ERC2981.sol";
    import { Ownable } from "solady/src/auth/Ownable.sol";
    import {
        Initializable
    } from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol";
    /**
     * @title  ERC1155ContractMetadataCloneable
     * @author James Wenzel (emo.eth)
     * @author Ryan Ghods (ralxz.eth)
     * @author Stephan Min (stephanm.eth)
     * @author Michael Cohen (notmichael.eth)
     * @notice A cloneable token contract that extends ERC-1155
     *         with additional metadata and ownership capabilities.
     */
    contract ERC1155ContractMetadataCloneable is
        ERC1155ConduitPreapproved,
        TokenTransferValidator,
        ERC2981,
        Ownable,
        IERC1155ContractMetadata,
        Initializable
    {
        /// @notice A struct containing the token supply info per token id.
        mapping(uint256 => TokenSupply) _tokenSupply;
        /// @notice The total number of tokens minted by address.
        mapping(address => uint256) _totalMintedByUser;
        /// @notice The total number of tokens minted per token id by address.
        mapping(address => mapping(uint256 => uint256)) _totalMintedByUserPerToken;
        /// @notice The name of the token.
        string internal _name;
        /// @notice The symbol of the token.
        string internal _symbol;
        /// @notice The base URI for token metadata.
        string internal _baseURI;
        /// @notice The contract URI for contract metadata.
        string internal _contractURI;
        /// @notice The provenance hash for guaranteeing metadata order
        ///         for random reveals.
        bytes32 internal _provenanceHash;
        /// @notice The allowed contract that can configure SeaDrop parameters.
        address internal _CONFIGURER;
        /**
         * @dev Reverts if the sender is not the owner or the allowed
         *      configurer contract.
         *
         *      This is used as a function instead of a modifier
         *      to save contract space when used multiple times.
         */
        function _onlyOwnerOrConfigurer() internal view {
            if (msg.sender != _CONFIGURER && msg.sender != owner()) {
                revert Unauthorized();
            }
        }
        /**
         * @notice Deploy the token contract.
         *
         * @param allowedConfigurer The address of the contract allowed to
         *                          configure parameters. Also contains SeaDrop
         *                          implementation code.
         * @param name_             The name of the token.
         * @param symbol_           The symbol of the token.
         */
        function __ERC1155ContractMetadataCloneable_init(
            address allowedConfigurer,
            string memory name_,
            string memory symbol_
        ) internal onlyInitializing {
            // Set the name of the token.
            _name = name_;
            // Set the symbol of the token.
            _symbol = symbol_;
            // Set the allowed configurer contract to interact with this contract.
            _CONFIGURER = allowedConfigurer;
        }
        /**
         * @notice Sets the base URI for the token metadata and emits an event.
         *
         * @param newBaseURI The new base URI to set.
         */
        function setBaseURI(string calldata newBaseURI) external override {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Set the new base URI.
            _baseURI = newBaseURI;
            // Emit an event with the update.
            emit BatchMetadataUpdate(0, type(uint256).max);
        }
        /**
         * @notice Sets the contract URI for contract metadata.
         *
         * @param newContractURI The new contract URI.
         */
        function setContractURI(string calldata newContractURI) external override {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Set the new contract URI.
            _contractURI = newContractURI;
            // Emit an event with the update.
            emit ContractURIUpdated(newContractURI);
        }
        /**
         * @notice Emit an event notifying metadata updates for
         *         a range of token ids, according to EIP-4906.
         *
         * @param fromTokenId The start token id.
         * @param toTokenId   The end token id.
         */
        function emitBatchMetadataUpdate(
            uint256 fromTokenId,
            uint256 toTokenId
        ) external {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Emit an event with the update.
            if (fromTokenId == toTokenId) {
                // If only one token is being updated, use the event
                // in the 1155 spec.
                emit URI(uri(fromTokenId), fromTokenId);
            } else {
                emit BatchMetadataUpdate(fromTokenId, toTokenId);
            }
        }
        /**
         * @notice Sets the max token supply and emits an event.
         *
         * @param tokenId      The token id to set the max supply for.
         * @param newMaxSupply The new max supply to set.
         */
        function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Ensure the max supply does not exceed the maximum value of uint64,
            // a limit due to the storage of bit-packed variables in TokenSupply,
            if (newMaxSupply > 2 ** 64 - 1) {
                revert CannotExceedMaxSupplyOfUint64(newMaxSupply);
            }
            // Set the new max supply.
            _tokenSupply[tokenId].maxSupply = uint64(newMaxSupply);
            // Emit an event with the update.
            emit MaxSupplyUpdated(tokenId, newMaxSupply);
        }
        /**
         * @notice Sets the provenance hash and emits an event.
         *
         *         The provenance hash is used for random reveals, which
         *         is a hash of the ordered metadata to show it has not been
         *         modified after mint started.
         *
         *         This function will revert if the provenance hash has already
         *         been set, so be sure to carefully set it only once.
         *
         * @param newProvenanceHash The new provenance hash to set.
         */
        function setProvenanceHash(bytes32 newProvenanceHash) external {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Keep track of the old provenance hash for emitting with the event.
            bytes32 oldProvenanceHash = _provenanceHash;
            // Revert if the provenance hash has already been set.
            if (oldProvenanceHash != bytes32(0)) {
                revert ProvenanceHashCannotBeSetAfterAlreadyBeingSet();
            }
            // Set the new provenance hash.
            _provenanceHash = newProvenanceHash;
            // Emit an event with the update.
            emit ProvenanceHashUpdated(oldProvenanceHash, newProvenanceHash);
        }
        /**
         * @notice Sets the default royalty information.
         *
         * Requirements:
         *
         * - `receiver` cannot be the zero address.
         * - `feeNumerator` cannot be greater than the fee denominator of 10_000 basis points.
         */
        function setDefaultRoyalty(address receiver, uint96 feeNumerator) external {
            // Ensure the sender is only the owner or configurer contract.
            _onlyOwnerOrConfigurer();
            // Set the default royalty.
            // ERC2981 implementation ensures feeNumerator <= feeDenominator
            // and receiver != address(0).
            _setDefaultRoyalty(receiver, feeNumerator);
            // Emit an event with the updated params.
            emit RoyaltyInfoUpdated(receiver, feeNumerator);
        }
        /**
         * @notice Returns the name of the token.
         */
        function name() external view returns (string memory) {
            return _name;
        }
        /**
         * @notice Returns the symbol of the token.
         */
        function symbol() external view returns (string memory) {
            return _symbol;
        }
        /**
         * @notice Returns the base URI for token metadata.
         */
        function baseURI() external view override returns (string memory) {
            return _baseURI;
        }
        /**
         * @notice Returns the contract URI for contract metadata.
         */
        function contractURI() external view override returns (string memory) {
            return _contractURI;
        }
        /**
         * @notice Returns the max token supply for a token id.
         */
        function maxSupply(uint256 tokenId) external view returns (uint256) {
            return _tokenSupply[tokenId].maxSupply;
        }
        /**
         * @notice Returns the total supply for a token id.
         */
        function totalSupply(uint256 tokenId) external view returns (uint256) {
            return _tokenSupply[tokenId].totalSupply;
        }
        /**
         * @notice Returns the total minted for a token id.
         */
        function totalMinted(uint256 tokenId) external view returns (uint256) {
            return _tokenSupply[tokenId].totalMinted;
        }
        /**
         * @notice Returns the provenance hash.
         *         The provenance hash is used for random reveals, which
         *         is a hash of the ordered metadata to show it is unmodified
         *         after mint has started.
         */
        function provenanceHash() external view override returns (bytes32) {
            return _provenanceHash;
        }
        /**
         * @notice Returns the URI for token metadata.
         *
         *         This implementation returns the same URI for *all* token types.
         *         It relies on the token type ID substitution mechanism defined
         *         in the EIP to replace {id} with the token id.
         *
         * @custom:param tokenId The token id to get the URI for.
         */
        function uri(
            uint256 /* tokenId */
        ) public view virtual override returns (string memory) {
            // Return the base URI.
            return _baseURI;
        }
        /**
         * @notice Returns the transfer validation function used.
         */
        function getTransferValidationFunction()
            external
            pure
            returns (bytes4 functionSignature, bool isViewFunction)
        {
            functionSignature = ITransferValidator1155.validateTransfer.selector;
            isViewFunction = true;
        }
        /**
         * @notice Set the transfer validator. Only callable by the token owner.
         */
        function setTransferValidator(address newValidator) external onlyOwner {
            // Set the new transfer validator.
            _setTransferValidator(newValidator);
        }
        /// @dev Override this function to return true if `_beforeTokenTransfer` is used.
        function _useBeforeTokenTransfer() internal view virtual override returns (bool) {
            return true;
        }
        /**
         * @dev Hook that is called before any token transfer.
         *      This includes minting and burning.
         */
        function _beforeTokenTransfer(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory /* data */
        ) internal virtual override {
            if (from != address(0) && to != address(0)) {
                // Call the transfer validator if one is set.
                address transferValidator = _transferValidator;
                if (transferValidator != address(0)) {
                    for (uint256 i = 0; i < ids.length; i++) {
                        ITransferValidator1155(transferValidator).validateTransfer(
                            msg.sender,
                            from,
                            to,
                            ids[i],
                            amounts[i]
                        );
                    }
                }
            }
        }
        /**
         * @notice Returns whether the interface is supported.
         *
         * @param interfaceId The interface id to check against.
         */
        function supportsInterface(
            bytes4 interfaceId
        ) public view virtual override(ERC1155, ERC2981) returns (bool) {
            return
                interfaceId == type(IERC1155ContractMetadata).interfaceId ||
                interfaceId == type(ICreatorToken).interfaceId ||
                interfaceId == type(ILegacyCreatorToken).interfaceId ||
                interfaceId == 0x49064906 || // ERC-4906 (MetadataUpdate)
                ERC2981.supportsInterface(interfaceId) ||
                // ERC1155 returns supportsInterface true for
                //     ERC165, ERC1155, ERC1155MetadataURI
                ERC1155.supportsInterface(interfaceId);
        }
        /**
         * @dev Adds to the internal counters for a mint.
         *
         * @param to     The address to mint to.
         * @param id     The token id to mint.
         * @param amount The quantity to mint.
         * @param data   The data to pass if receiver is a contract.
         */
        function _mint(
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) internal virtual override {
            // Increment mint counts.
            _incrementMintCounts(to, id, amount);
            ERC1155._mint(to, id, amount, data);
        }
        /**
         * @dev Adds to the internal counters for a batch mint.
         *
         * @param to      The address to mint to.
         * @param ids     The token ids to mint.
         * @param amounts The quantities to mint.
         * @param data    The data to pass if receiver is a contract.
         */
        function _batchMint(
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual override {
            // Put ids length on the stack to save MLOADs.
            uint256 idsLength = ids.length;
            for (uint256 i = 0; i < idsLength; ) {
                // Increment mint counts.
                _incrementMintCounts(to, ids[i], amounts[i]);
                unchecked {
                    ++i;
                }
            }
            ERC1155._batchMint(to, ids, amounts, data);
        }
        /**
         * @dev Subtracts from the internal counters for a burn.
         *
         * @param by     The address calling the burn.
         * @param from   The address to burn from.
         * @param id     The token id to burn.
         * @param amount The amount to burn.
         */
        function _burn(
            address by,
            address from,
            uint256 id,
            uint256 amount
        ) internal virtual override {
            // Reduce the supply.
            _reduceSupplyOnBurn(id, amount);
            ERC1155._burn(by, from, id, amount);
        }
        /**
         * @dev Subtracts from the internal counters for a batch burn.
         *
         * @param by      The address calling the burn.
         * @param from    The address to burn from.
         * @param ids     The token ids to burn.
         * @param amounts The amounts to burn.
         */
        function _batchBurn(
            address by,
            address from,
            uint256[] memory ids,
            uint256[] memory amounts
        ) internal virtual override {
            // Put ids length on the stack to save MLOADs.
            uint256 idsLength = ids.length;
            for (uint256 i = 0; i < idsLength; ) {
                // Reduce the supply.
                _reduceSupplyOnBurn(ids[i], amounts[i]);
                unchecked {
                    ++i;
                }
            }
            ERC1155._batchBurn(by, from, ids, amounts);
        }
        function _reduceSupplyOnBurn(uint256 id, uint256 amount) internal {
            // Get the current token supply.
            TokenSupply storage tokenSupply = _tokenSupply[id];
            // Reduce the totalSupply.
            unchecked {
                tokenSupply.totalSupply -= uint64(amount);
            }
        }
        /**
         * @dev Internal function to increment mint counts.
         *
         *      Note that this function does not check if the mint exceeds
         *      maxSupply, which should be validated before this function is called.
         *
         * @param to     The address to mint to.
         * @param id     The token id to mint.
         * @param amount The quantity to mint.
         */
        function _incrementMintCounts(
            address to,
            uint256 id,
            uint256 amount
        ) internal {
            // Get the current token supply.
            TokenSupply storage tokenSupply = _tokenSupply[id];
            if (tokenSupply.totalMinted + amount > tokenSupply.maxSupply) {
                revert MintExceedsMaxSupply(
                    tokenSupply.totalMinted + amount,
                    tokenSupply.maxSupply
                );
            }
            // Increment supply and number minted.
            // Can be unchecked because maxSupply cannot be set to exceed uint64.
            unchecked {
                tokenSupply.totalSupply += uint64(amount);
                tokenSupply.totalMinted += uint64(amount);
                // Increment total minted by user.
                _totalMintedByUser[to] += amount;
                // Increment total minted by user per token.
                _totalMintedByUserPerToken[to][id] += amount;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { PublicDrop } from "./ERC1155SeaDropStructs.sol";
    import { CreatorPayout } from "./SeaDropStructs.sol";
    library ERC1155SeaDropContractOffererStorage {
        struct Layout {
            /// @notice The allowed Seaport addresses that can mint.
            mapping(address => bool) _allowedSeaport;
            /// @notice The enumerated allowed Seaport addresses.
            address[] _enumeratedAllowedSeaport;
            /// @notice The public drop data.
            mapping(uint256 => PublicDrop) _publicDrops;
            /// @notice The enumerated public drop indexes.
            uint256[] _enumeratedPublicDropIndexes;
            /// @notice The creator payout addresses and basis points.
            CreatorPayout[] _creatorPayouts;
            /// @notice The allow list merkle root.
            bytes32 _allowListMerkleRoot;
            /// @notice The allowed fee recipients.
            mapping(address => bool) _allowedFeeRecipients;
            /// @notice The enumerated allowed fee recipients.
            address[] _enumeratedFeeRecipients;
            /// @notice The allowed server-side signers.
            mapping(address => bool) _allowedSigners;
            /// @notice The enumerated allowed signers.
            address[] _enumeratedSigners;
            /// @notice The used signature digests.
            mapping(bytes32 => bool) _usedDigests;
            /// @notice The allowed payers.
            mapping(address => bool) _allowedPayers;
            /// @notice The enumerated allowed payers.
            address[] _enumeratedPayers;
        }
        bytes32 internal constant STORAGE_SLOT =
            bytes32(
                uint256(
                    keccak256("contracts.storage.ERC1155SeaDropContractOfferer")
                ) - 1
            );
        function layout() internal pure returns (Layout storage l) {
            bytes32 slot = STORAGE_SLOT;
            assembly {
                l.slot := slot
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { PublicDrop } from "./ERC1155SeaDropStructs.sol";
    import { SeaDropErrorsAndEvents } from "./SeaDropErrorsAndEvents.sol";
    interface ERC1155SeaDropErrorsAndEvents is SeaDropErrorsAndEvents {
        /**
         * @dev Revert with an error if an empty PublicDrop is provided
         *      for an already-empty public drop.
         */
        error PublicDropStageNotPresent();
        /**
         * @dev Revert with an error if the mint quantity exceeds the
         *      max minted per wallet for a certain token id.
         */
        error MintQuantityExceedsMaxMintedPerWalletForTokenId(
            uint256 tokenId,
            uint256 total,
            uint256 allowed
        );
        /**
         * @dev Revert with an error if the target token id to mint is not within
         *      the drop stage range.
         */
        error TokenIdNotWithinDropStageRange(
            uint256 tokenId,
            uint256 startTokenId,
            uint256 endTokenId
        );
        /**
         *  @notice Revert with an error if the number of maxSupplyAmounts doesn't
         *          match the number of maxSupplyTokenIds.
         */
        error MaxSupplyMismatch();
        /**
         *  @notice Revert with an error if the number of mint tokenIds doesn't
         *          match the number of mint amounts.
         */
        error MintAmountsMismatch();
        /**
         * @notice Revert with an error if the mint order offer contains
         *         a duplicate tokenId.
         */
        error OfferContainsDuplicateTokenId(uint256 tokenId);
        /**
         * @dev Revert if the fromTokenId is greater than the toTokenId.
         */
        error InvalidFromAndToTokenId(uint256 fromTokenId, uint256 toTokenId);
        /**
         *  @notice Revert with an error if the number of publicDropIndexes doesn't
         *          match the number of publicDrops.
         */
        error PublicDropsMismatch();
        /**
         * @dev An event with updated public drop data.
         */
        event PublicDropUpdated(PublicDrop publicDrop, uint256 index);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol";
    /**
     * @notice A struct defining public drop data.
     *         Designed to fit efficiently in two storage slots.
     *
     * @param startPrice               The start price per token. (Up to 1.2m
     *                                 of native token, e.g. ETH, MATIC)
     * @param endPrice                 The end price per token. If this differs
     *                                 from startPrice, the current price will
     *                                 be calculated based on the current time.
     * @param startTime                The start time, ensure this is not zero.
     * @param endTime                  The end time, ensure this is not zero.
     * @param restrictFeeRecipients    If false, allow any fee recipient;
     *                                 if true, check fee recipient is allowed.
     * @param paymentToken             The payment token address. Null for
     *                                 native token.
     * @param fromTokenId              The start token id for the stage.
     * @param toTokenId                The end token id for the stage.
     * @param maxTotalMintableByWallet Maximum total number of mints a user is
     *                                 allowed. (The limit for this field is
     *                                 2^16 - 1)
     * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user
     *                                 is allowed for the token id. (The limit for
     *                                 this field is 2^16 - 1)
     * @param feeBps                   Fee out of 10_000 basis points to be
     *                                 collected.
     */
    struct PublicDrop {
        // slot 1
        uint80 startPrice; // 80/512 bits
        uint80 endPrice; // 160/512 bits
        uint40 startTime; // 200/512 bits
        uint40 endTime; // 240/512 bits
        bool restrictFeeRecipients; // 248/512 bits
        // uint8 unused;
        // slot 2
        address paymentToken; // 408/512 bits
        uint24 fromTokenId; // 432/512 bits
        uint24 toTokenId; // 456/512 bits
        uint16 maxTotalMintableByWallet; // 472/512 bits
        uint16 maxTotalMintableByWalletPerToken; // 488/512 bits
        uint16 feeBps; // 504/512 bits
    }
    /**
     * @notice A struct defining mint params for an allow list.
     *         An allow list leaf will be composed of `msg.sender` and
     *         the following params.
     *
     *         Note: Since feeBps is encoded in the leaf, backend should ensure
     *         that feeBps is acceptable before generating a proof.
     *
     * @param startPrice               The start price per token. (Up to 1.2m
     *                                 of native token, e.g. ETH, MATIC)
     * @param endPrice                 The end price per token. If this differs
     *                                 from startPrice, the current price will
     *                                 be calculated based on the current time.
     * @param startTime                The start time, ensure this is not zero.
     * @param endTime                  The end time, ensure this is not zero.
     * @param paymentToken             The payment token for the mint. Null for
     *                                 native token.
     * @param fromTokenId              The start token id for the stage.
     * @param toTokenId                The end token id for the stage.
     * @param maxTotalMintableByWallet Maximum total number of mints a user is
     *                                 allowed.
     * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user
     *                                 is allowed for the token id.
     * @param maxTokenSupplyForStage   The limit of token supply this stage can
     *                                 mint within.
     * @param dropStageIndex           The drop stage index to emit with the event
     *                                 for analytical purposes. This should be
     *                                 non-zero since the public mint emits with
     *                                 index zero.
     * @param feeBps                   Fee out of 10_000 basis points to be
     *                                 collected.
     * @param restrictFeeRecipients    If false, allow any fee recipient;
     *                                 if true, check fee recipient is allowed.
     */
    struct MintParams {
        uint256 startPrice;
        uint256 endPrice;
        uint256 startTime;
        uint256 endTime;
        address paymentToken;
        uint256 fromTokenId;
        uint256 toTokenId;
        uint256 maxTotalMintableByWallet;
        uint256 maxTotalMintableByWalletPerToken;
        uint256 maxTokenSupplyForStage;
        uint256 dropStageIndex; // non-zero
        uint256 feeBps;
        bool restrictFeeRecipients;
    }
    /**
     * @dev Struct containing internal SeaDrop implementation logic
     *      mint details to avoid stack too deep.
     *
     * @param feeRecipient The fee recipient.
     * @param payer        The payer of the mint.
     * @param minter       The mint recipient.
     * @param tokenIds     The tokenIds to mint.
     * @param quantities   The number of tokens to mint per tokenId.
     * @param withEffects  Whether to apply state changes of the mint.
     */
    struct MintDetails {
        address feeRecipient;
        address payer;
        address minter;
        uint256[] tokenIds;
        uint256[] quantities;
        bool withEffects;
    }
    /**
     * @notice A struct to configure multiple contract options in one transaction.
     */
    struct MultiConfigureStruct {
        uint256[] maxSupplyTokenIds;
        uint256[] maxSupplyAmounts;
        string baseURI;
        string contractURI;
        PublicDrop[] publicDrops;
        uint256[] publicDropsIndexes;
        string dropURI;
        AllowListData allowListData;
        CreatorPayout[] creatorPayouts;
        bytes32 provenanceHash;
        address[] allowedFeeRecipients;
        address[] disallowedFeeRecipients;
        address[] allowedPayers;
        address[] disallowedPayers;
        // Server-signed
        address[] allowedSigners;
        address[] disallowedSigners;
        // ERC-2981
        address royaltyReceiver;
        uint96 royaltyBps;
        // Mint
        address mintRecipient;
        uint256[] mintTokenIds;
        uint256[] mintAmounts;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    /**
     * @notice A struct defining a creator payout address and basis points.
     *
     * @param payoutAddress The payout address.
     * @param basisPoints   The basis points to pay out to the creator.
     *                      The total creator payouts must equal 10_000 bps.
     */
    struct CreatorPayout {
        address payoutAddress;
        uint16 basisPoints;
    }
    /**
     * @notice A struct defining allow list data (for minting an allow list).
     *
     * @param merkleRoot    The merkle root for the allow list.
     * @param publicKeyURIs If the allowListURI is encrypted, a list of URIs
     *                      pointing to the public keys. Empty if unencrypted.
     * @param allowListURI  The URI for the allow list.
     */
    struct AllowListData {
        bytes32 merkleRoot;
        string[] publicKeyURIs;
        string allowListURI;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { ERC1155 } from "solady/src/tokens/ERC1155.sol";
    /**
     * @title  ERC1155ConduitPreapproved
     * @notice Solady's ERC1155 with the OpenSea conduit preapproved.
     */
    abstract contract ERC1155ConduitPreapproved is ERC1155 {
        /// @dev The canonical OpenSea conduit.
        address internal constant _CONDUIT =
            0x1E0049783F008A0085193E00003D00cd54003c71;
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes calldata data
        ) public virtual override {
            _safeTransfer(_by(), from, to, id, amount, data);
        }
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            uint256[] calldata amounts,
            bytes calldata data
        ) public virtual override {
            _safeBatchTransfer(_by(), from, to, ids, amounts, data);
        }
        function isApprovedForAll(
            address owner,
            address operator
        ) public view virtual override returns (bool) {
            if (operator == _CONDUIT) return true;
            return ERC1155.isApprovedForAll(owner, operator);
        }
        function _by() internal view virtual returns (address result) {
            assembly {
                // `msg.sender == _CONDUIT ? address(0) : msg.sender`.
                result := mul(iszero(eq(caller(), _CONDUIT)), caller())
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    /// @notice Simple ERC1155 implementation.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol)
    /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
    /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol)
    ///
    /// @dev Note:
    /// The ERC1155 standard allows for self-approvals.
    /// For performance, this implementation WILL NOT revert for such actions.
    /// Please add any checks with overrides if desired.
    abstract contract ERC1155 {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The lengths of the input arrays are not the same.
        error ArrayLengthsMismatch();
        /// @dev Cannot mint or transfer to the zero address.
        error TransferToZeroAddress();
        /// @dev The recipient's balance has overflowed.
        error AccountBalanceOverflow();
        /// @dev Insufficient balance.
        error InsufficientBalance();
        /// @dev Only the token owner or an approved account can manage the tokens.
        error NotOwnerNorApproved();
        /// @dev Cannot safely transfer to a contract that does not implement
        /// the ERC1155Receiver interface.
        error TransferToNonERC1155ReceiverImplementer();
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           EVENTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Emitted when `amount` of token `id` is transferred
        /// from `from` to `to` by `operator`.
        event TransferSingle(
            address indexed operator,
            address indexed from,
            address indexed to,
            uint256 id,
            uint256 amount
        );
        /// @dev Emitted when `amounts` of token `ids` are transferred
        /// from `from` to `to` by `operator`.
        event TransferBatch(
            address indexed operator,
            address indexed from,
            address indexed to,
            uint256[] ids,
            uint256[] amounts
        );
        /// @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 Emitted when the Uniform Resource Identifier (URI) for token `id`
        /// is updated to `value`. This event is not used in the base contract.
        /// You may need to emit this event depending on your URI logic.
        ///
        /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
        event URI(string value, uint256 indexed id);
        /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`.
        uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE =
            0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62;
        /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`.
        uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE =
            0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb;
        /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
        uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
            0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          STORAGE                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The `ownerSlotSeed` of a given owner is given by.
        /// ```
        ///     let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))
        /// ```
        ///
        /// The balance slot of `owner` is given by.
        /// ```
        ///     mstore(0x20, ownerSlotSeed)
        ///     mstore(0x00, id)
        ///     let balanceSlot := keccak256(0x00, 0x40)
        /// ```
        ///
        /// The operator approval slot of `owner` is given by.
        /// ```
        ///     mstore(0x20, ownerSlotSeed)
        ///     mstore(0x00, operator)
        ///     let operatorApprovalSlot := keccak256(0x0c, 0x34)
        /// ```
        uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      ERC1155 METADATA                      */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns the URI for token `id`.
        ///
        /// You can either return the same templated URI for all token IDs,
        /// (e.g. "https://example.com/api/{id}.json"),
        /// or return a unique URI for each `id`.
        ///
        /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
        function uri(uint256 id) public view virtual returns (string memory);
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          ERC1155                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns the amount of `id` owned by `owner`.
        function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
                mstore(0x14, owner)
                mstore(0x00, id)
                result := sload(keccak256(0x00, 0x40))
            }
        }
        /// @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(0x20, _ERC1155_MASTER_SLOT_SEED)
                mstore(0x14, owner)
                mstore(0x00, operator)
                result := sload(keccak256(0x0c, 0x34))
            }
        }
        /// @dev Sets whether `operator` is approved to manage the tokens of the caller.
        ///
        /// Emits a {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(0x20, _ERC1155_MASTER_SLOT_SEED)
                mstore(0x14, caller())
                mstore(0x00, operator)
                sstore(keccak256(0x0c, 0x34), isApproved)
                // Emit the {ApprovalForAll} event.
                mstore(0x00, isApproved)
                // forgefmt: disable-next-line
                log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
            }
        }
        /// @dev Transfers `amount` of `id` from `from` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - `from` must have at least `amount` of `id`.
        /// - If the caller is not `from`,
        ///   it must be approved to manage the tokens of `from`.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.
        ///
        /// Emits a {Transfer} event.
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes calldata data
        ) public virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, to, _single(id), _single(amount), data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
                let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
                mstore(0x20, fromSlotSeed)
                // Clear the upper 96 bits.
                from := shr(96, fromSlotSeed)
                to := shr(96, toSlotSeed)
                // Revert if `to` is the zero address.
                if iszero(to) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                // If the caller is not `from`, do the authorization check.
                if iszero(eq(caller(), from)) {
                    mstore(0x00, caller())
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Subtract and store the updated balance of `from`.
                {
                    mstore(0x00, id)
                    let fromBalanceSlot := keccak256(0x00, 0x40)
                    let fromBalance := sload(fromBalanceSlot)
                    if gt(amount, fromBalance) {
                        mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(fromBalanceSlot, sub(fromBalance, amount))
                }
                // Increase and store the updated balance of `to`.
                {
                    mstore(0x20, toSlotSeed)
                    let toBalanceSlot := keccak256(0x00, 0x40)
                    let toBalanceBefore := sload(toBalanceSlot)
                    let toBalanceAfter := add(toBalanceBefore, amount)
                    if lt(toBalanceAfter, toBalanceBefore) {
                        mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(toBalanceSlot, toBalanceAfter)
                }
                // Emit a {TransferSingle} event.
                mstore(0x20, amount)
                log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to)
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, to, _single(id), _single(amount), data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                // Do the {onERC1155Received} check if `to` is a smart contract.
                if extcodesize(to) {
                    // Prepare the calldata.
                    let m := mload(0x40)
                    // `onERC1155Received(address,address,uint256,uint256,bytes)`.
                    mstore(m, 0xf23a6e61)
                    mstore(add(m, 0x20), caller())
                    mstore(add(m, 0x40), from)
                    mstore(add(m, 0x60), id)
                    mstore(add(m, 0x80), amount)
                    mstore(add(m, 0xa0), 0xa0)
                    calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length))
                    // Revert if the call reverts.
                    if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) {
                        if returndatasize() {
                            // Bubble up the revert if the call reverts.
                            returndatacopy(0x00, 0x00, returndatasize())
                            revert(0x00, returndatasize())
                        }
                        mstore(m, 0)
                    }
                    // Load the returndata and compare it with the function selector.
                    if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
                        mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
        }
        /// @dev Transfers `amounts` of `ids` from `from` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - `from` must have at least `amount` of `id`.
        /// - `ids` and `amounts` must have the same length.
        /// - If the caller is not `from`,
        ///   it must be approved to manage the tokens of `from`.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.
        ///
        /// Emits a {TransferBatch} event.
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            uint256[] calldata amounts,
            bytes calldata data
        ) public virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, to, ids, amounts, data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(eq(ids.length, amounts.length)) {
                    mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
                    revert(0x1c, 0x04)
                }
                let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
                let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
                mstore(0x20, fromSlotSeed)
                // Clear the upper 96 bits.
                from := shr(96, fromSlotSeed)
                to := shr(96, toSlotSeed)
                // Revert if `to` is the zero address.
                if iszero(to) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                // If the caller is not `from`, do the authorization check.
                if iszero(eq(caller(), from)) {
                    mstore(0x00, caller())
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Loop through all the `ids` and update the balances.
                {
                    let end := shl(5, ids.length)
                    for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } {
                        let amount := calldataload(add(amounts.offset, i))
                        // Subtract and store the updated balance of `from`.
                        {
                            mstore(0x20, fromSlotSeed)
                            mstore(0x00, calldataload(add(ids.offset, i)))
                            let fromBalanceSlot := keccak256(0x00, 0x40)
                            let fromBalance := sload(fromBalanceSlot)
                            if gt(amount, fromBalance) {
                                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(fromBalanceSlot, sub(fromBalance, amount))
                        }
                        // Increase and store the updated balance of `to`.
                        {
                            mstore(0x20, toSlotSeed)
                            let toBalanceSlot := keccak256(0x00, 0x40)
                            let toBalanceBefore := sload(toBalanceSlot)
                            let toBalanceAfter := add(toBalanceBefore, amount)
                            if lt(toBalanceAfter, toBalanceBefore) {
                                mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(toBalanceSlot, toBalanceAfter)
                        }
                    }
                }
                // Emit a {TransferBatch} event.
                {
                    let m := mload(0x40)
                    // Copy the `ids`.
                    mstore(m, 0x40)
                    let n := add(0x20, shl(5, ids.length))
                    let o := add(m, 0x40)
                    calldatacopy(o, sub(ids.offset, 0x20), n)
                    // Copy the `amounts`.
                    mstore(add(m, 0x20), add(0x40, n))
                    o := add(o, n)
                    n := add(0x20, shl(5, amounts.length))
                    calldatacopy(o, sub(amounts.offset, 0x20), n)
                    n := sub(add(o, n), m)
                    // Do the emit.
                    log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to)
                }
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransferCalldata(from, to, ids, amounts, data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                // Do the {onERC1155BatchReceived} check if `to` is a smart contract.
                if extcodesize(to) {
                    let m := mload(0x40)
                    // Prepare the calldata.
                    // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
                    mstore(m, 0xbc197c81)
                    mstore(add(m, 0x20), caller())
                    mstore(add(m, 0x40), from)
                    // Copy the `ids`.
                    mstore(add(m, 0x60), 0xa0)
                    let n := add(0x20, shl(5, ids.length))
                    let o := add(m, 0xc0)
                    calldatacopy(o, sub(ids.offset, 0x20), n)
                    // Copy the `amounts`.
                    let s := add(0xa0, n)
                    mstore(add(m, 0x80), s)
                    o := add(o, n)
                    n := add(0x20, shl(5, amounts.length))
                    calldatacopy(o, sub(amounts.offset, 0x20), n)
                    // Copy the `data`.
                    mstore(add(m, 0xa0), add(s, n))
                    o := add(o, n)
                    n := add(0x20, data.length)
                    calldatacopy(o, sub(data.offset, 0x20), n)
                    n := sub(add(o, n), add(m, 0x1c))
                    // Revert if the call reverts.
                    if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) {
                        if returndatasize() {
                            // Bubble up the revert if the call reverts.
                            returndatacopy(0x00, 0x00, returndatasize())
                            revert(0x00, returndatasize())
                        }
                        mstore(m, 0)
                    }
                    // Load the returndata and compare it with the function selector.
                    if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
                        mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
        }
        /// @dev Returns the amounts of `ids` for `owners.
        ///
        /// Requirements:
        /// - `owners` and `ids` must have the same length.
        function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
            public
            view
            virtual
            returns (uint256[] memory balances)
        {
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(eq(ids.length, owners.length)) {
                    mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
                    revert(0x1c, 0x04)
                }
                balances := mload(0x40)
                mstore(balances, ids.length)
                let o := add(balances, 0x20)
                let end := shl(5, ids.length)
                mstore(0x40, add(end, o))
                // Loop through all the `ids` and load the balances.
                for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } {
                    let owner := calldataload(add(owners.offset, i))
                    mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)))
                    mstore(0x00, calldataload(add(ids.offset, i)))
                    mstore(add(o, i), sload(keccak256(0x00, 0x40)))
                }
            }
        }
        /// @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, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c.
                result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c))
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  INTERNAL MINT FUNCTIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Mints `amount` of `id` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.
        ///
        /// Emits a {Transfer} event.
        function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                let to_ := shl(96, to)
                // Revert if `to` is the zero address.
                if iszero(to_) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                // Increase and store the updated balance of `to`.
                {
                    mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
                    mstore(0x14, to)
                    mstore(0x00, id)
                    let toBalanceSlot := keccak256(0x00, 0x40)
                    let toBalanceBefore := sload(toBalanceSlot)
                    let toBalanceAfter := add(toBalanceBefore, amount)
                    if lt(toBalanceAfter, toBalanceBefore) {
                        mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(toBalanceSlot, toBalanceAfter)
                }
                // Emit a {TransferSingle} event.
                mstore(0x00, id)
                mstore(0x20, amount)
                log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(address(0), to, _single(id), _single(amount), data);
            }
            if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data);
        }
        /// @dev Mints `amounts` of `ids` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - `ids` and `amounts` must have the same length.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.
        ///
        /// Emits a {TransferBatch} event.
        function _batchMint(
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(address(0), to, ids, amounts, data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(eq(mload(ids), mload(amounts))) {
                    mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
                    revert(0x1c, 0x04)
                }
                let to_ := shl(96, to)
                // Revert if `to` is the zero address.
                if iszero(to_) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                // Loop through all the `ids` and update the balances.
                {
                    mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
                    let end := shl(5, mload(ids))
                    for { let i := 0 } iszero(eq(i, end)) {} {
                        i := add(i, 0x20)
                        let amount := mload(add(amounts, i))
                        // Increase and store the updated balance of `to`.
                        {
                            mstore(0x00, mload(add(ids, i)))
                            let toBalanceSlot := keccak256(0x00, 0x40)
                            let toBalanceBefore := sload(toBalanceSlot)
                            let toBalanceAfter := add(toBalanceBefore, amount)
                            if lt(toBalanceAfter, toBalanceBefore) {
                                mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(toBalanceSlot, toBalanceAfter)
                        }
                    }
                }
                // Emit a {TransferBatch} event.
                {
                    let m := mload(0x40)
                    // Copy the `ids`.
                    mstore(m, 0x40)
                    let n := add(0x20, shl(5, mload(ids)))
                    let o := add(m, 0x40)
                    pop(staticcall(gas(), 4, ids, n, o, n))
                    // Copy the `amounts`.
                    mstore(add(m, 0x20), add(0x40, returndatasize()))
                    o := add(o, returndatasize())
                    n := add(0x20, shl(5, mload(amounts)))
                    pop(staticcall(gas(), 4, amounts, n, o, n))
                    n := sub(add(o, returndatasize()), m)
                    // Do the emit.
                    log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
                }
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(address(0), to, ids, amounts, data);
            }
            if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data);
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  INTERNAL BURN FUNCTIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Equivalent to `_burn(address(0), from, id, amount)`.
        function _burn(address from, uint256 id, uint256 amount) internal virtual {
            _burn(address(0), from, id, amount);
        }
        /// @dev Destroys `amount` of `id` from `from`.
        ///
        /// Requirements:
        /// - `from` must have at least `amount` of `id`.
        /// - If `by` is not the zero address, it must be either `from`,
        ///   or approved to manage the tokens of `from`.
        ///
        /// Emits a {Transfer} event.
        function _burn(address by, address from, uint256 id, uint256 amount) internal virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, address(0), _single(id), _single(amount), "");
            }
            /// @solidity memory-safe-assembly
            assembly {
                let from_ := shl(96, from)
                mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
                // If `by` is not the zero address, and not equal to `from`,
                // check if it is approved to manage all the tokens of `from`.
                if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) {
                    mstore(0x00, by)
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Decrease and store the updated balance of `from`.
                {
                    mstore(0x00, id)
                    let fromBalanceSlot := keccak256(0x00, 0x40)
                    let fromBalance := sload(fromBalanceSlot)
                    if gt(amount, fromBalance) {
                        mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(fromBalanceSlot, sub(fromBalance, amount))
                }
                // Emit a {TransferSingle} event.
                mstore(0x00, id)
                mstore(0x20, amount)
                log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, address(0), _single(id), _single(amount), "");
            }
        }
        /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`.
        function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts)
            internal
            virtual
        {
            _batchBurn(address(0), from, ids, amounts);
        }
        /// @dev Destroys `amounts` of `ids` from `from`.
        ///
        /// Requirements:
        /// - `ids` and `amounts` must have the same length.
        /// - `from` must have at least `amounts` of `ids`.
        /// - If `by` is not the zero address, it must be either `from`,
        ///   or approved to manage the tokens of `from`.
        ///
        /// Emits a {TransferBatch} event.
        function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts)
            internal
            virtual
        {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, address(0), ids, amounts, "");
            }
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(eq(mload(ids), mload(amounts))) {
                    mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
                    revert(0x1c, 0x04)
                }
                let from_ := shl(96, from)
                mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
                // If `by` is not the zero address, and not equal to `from`,
                // check if it is approved to manage all the tokens of `from`.
                let by_ := shl(96, by)
                if iszero(or(iszero(by_), eq(by_, from_))) {
                    mstore(0x00, by)
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Loop through all the `ids` and update the balances.
                {
                    let end := shl(5, mload(ids))
                    for { let i := 0 } iszero(eq(i, end)) {} {
                        i := add(i, 0x20)
                        let amount := mload(add(amounts, i))
                        // Decrease and store the updated balance of `to`.
                        {
                            mstore(0x00, mload(add(ids, i)))
                            let fromBalanceSlot := keccak256(0x00, 0x40)
                            let fromBalance := sload(fromBalanceSlot)
                            if gt(amount, fromBalance) {
                                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(fromBalanceSlot, sub(fromBalance, amount))
                        }
                    }
                }
                // Emit a {TransferBatch} event.
                {
                    let m := mload(0x40)
                    // Copy the `ids`.
                    mstore(m, 0x40)
                    let n := add(0x20, shl(5, mload(ids)))
                    let o := add(m, 0x40)
                    pop(staticcall(gas(), 4, ids, n, o, n))
                    // Copy the `amounts`.
                    mstore(add(m, 0x20), add(0x40, returndatasize()))
                    o := add(o, returndatasize())
                    n := add(0x20, shl(5, mload(amounts)))
                    pop(staticcall(gas(), 4, amounts, n, o, n))
                    n := sub(add(o, returndatasize()), m)
                    // Do the emit.
                    log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
                }
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, address(0), ids, amounts, "");
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                INTERNAL APPROVAL FUNCTIONS                 */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Approve or remove the `operator` as an operator for `by`,
        /// without authorization checks.
        ///
        /// Emits a {ApprovalForAll} event.
        function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
            /// @solidity memory-safe-assembly
            assembly {
                // Convert to 0 or 1.
                isApproved := iszero(iszero(isApproved))
                // Update the `isApproved` for (`by`, `operator`).
                mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
                mstore(0x14, by)
                mstore(0x00, operator)
                sstore(keccak256(0x0c, 0x34), isApproved)
                // Emit the {ApprovalForAll} event.
                mstore(0x00, isApproved)
                let m := shr(96, not(0))
                log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator))
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                INTERNAL TRANSFER FUNCTIONS                 */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`.
        function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data)
            internal
            virtual
        {
            _safeTransfer(address(0), from, to, id, amount, data);
        }
        /// @dev Transfers `amount` of `id` from `from` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - `from` must have at least `amount` of `id`.
        /// - If `by` is not the zero address, it must be either `from`,
        ///   or approved to manage the tokens of `from`.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.
        ///
        /// Emits a {Transfer} event.
        function _safeTransfer(
            address by,
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) internal virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, to, _single(id), _single(amount), data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                let from_ := shl(96, from)
                let to_ := shl(96, to)
                // Revert if `to` is the zero address.
                if iszero(to_) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
                // If `by` is not the zero address, and not equal to `from`,
                // check if it is approved to manage all the tokens of `from`.
                let by_ := shl(96, by)
                if iszero(or(iszero(by_), eq(by_, from_))) {
                    mstore(0x00, by)
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Subtract and store the updated balance of `from`.
                {
                    mstore(0x00, id)
                    let fromBalanceSlot := keccak256(0x00, 0x40)
                    let fromBalance := sload(fromBalanceSlot)
                    if gt(amount, fromBalance) {
                        mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(fromBalanceSlot, sub(fromBalance, amount))
                }
                // Increase and store the updated balance of `to`.
                {
                    mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
                    let toBalanceSlot := keccak256(0x00, 0x40)
                    let toBalanceBefore := sload(toBalanceSlot)
                    let toBalanceAfter := add(toBalanceBefore, amount)
                    if lt(toBalanceAfter, toBalanceBefore) {
                        mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    sstore(toBalanceSlot, toBalanceAfter)
                }
                // Emit a {TransferSingle} event.
                mstore(0x20, amount)
                // forgefmt: disable-next-line
                log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, to, _single(id), _single(amount), data);
            }
            if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data);
        }
        /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`.
        function _safeBatchTransfer(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {
            _safeBatchTransfer(address(0), from, to, ids, amounts, data);
        }
        /// @dev Transfers `amounts` of `ids` from `from` to `to`.
        ///
        /// Requirements:
        /// - `to` cannot be the zero address.
        /// - `ids` and `amounts` must have the same length.
        /// - `from` must have at least `amounts` of `ids`.
        /// - If `by` is not the zero address, it must be either `from`,
        ///   or approved to manage the tokens of `from`.
        /// - If `to` refers to a smart contract, it must implement
        ///   {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.
        ///
        /// Emits a {TransferBatch} event.
        function _safeBatchTransfer(
            address by,
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {
            if (_useBeforeTokenTransfer()) {
                _beforeTokenTransfer(from, to, ids, amounts, data);
            }
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(eq(mload(ids), mload(amounts))) {
                    mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
                    revert(0x1c, 0x04)
                }
                let from_ := shl(96, from)
                let to_ := shl(96, to)
                // Revert if `to` is the zero address.
                if iszero(to_) {
                    mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_)
                let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_)
                mstore(0x20, fromSlotSeed)
                // If `by` is not the zero address, and not equal to `from`,
                // check if it is approved to manage all the tokens of `from`.
                let by_ := shl(96, by)
                if iszero(or(iszero(by_), eq(by_, from_))) {
                    mstore(0x00, by)
                    if iszero(sload(keccak256(0x0c, 0x34))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Loop through all the `ids` and update the balances.
                {
                    let end := shl(5, mload(ids))
                    for { let i := 0 } iszero(eq(i, end)) {} {
                        i := add(i, 0x20)
                        let amount := mload(add(amounts, i))
                        // Subtract and store the updated balance of `from`.
                        {
                            mstore(0x20, fromSlotSeed)
                            mstore(0x00, mload(add(ids, i)))
                            let fromBalanceSlot := keccak256(0x00, 0x40)
                            let fromBalance := sload(fromBalanceSlot)
                            if gt(amount, fromBalance) {
                                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(fromBalanceSlot, sub(fromBalance, amount))
                        }
                        // Increase and store the updated balance of `to`.
                        {
                            mstore(0x20, toSlotSeed)
                            let toBalanceSlot := keccak256(0x00, 0x40)
                            let toBalanceBefore := sload(toBalanceSlot)
                            let toBalanceAfter := add(toBalanceBefore, amount)
                            if lt(toBalanceAfter, toBalanceBefore) {
                                mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                                revert(0x1c, 0x04)
                            }
                            sstore(toBalanceSlot, toBalanceAfter)
                        }
                    }
                }
                // Emit a {TransferBatch} event.
                {
                    let m := mload(0x40)
                    // Copy the `ids`.
                    mstore(m, 0x40)
                    let n := add(0x20, shl(5, mload(ids)))
                    let o := add(m, 0x40)
                    pop(staticcall(gas(), 4, ids, n, o, n))
                    // Copy the `amounts`.
                    mstore(add(m, 0x20), add(0x40, returndatasize()))
                    o := add(o, returndatasize())
                    n := add(0x20, shl(5, mload(amounts)))
                    pop(staticcall(gas(), 4, amounts, n, o, n))
                    n := sub(add(o, returndatasize()), m)
                    // Do the emit.
                    log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
                }
            }
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, to, ids, amounts, data);
            }
            if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data);
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                    HOOKS FOR OVERRIDING                    */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Override this function to return true if `_beforeTokenTransfer` is used.
        /// The is to help the compiler avoid producing dead bytecode.
        function _useBeforeTokenTransfer() internal view virtual returns (bool) {
            return false;
        }
        /// @dev Hook that is called before any token transfer.
        /// This includes minting and burning, as well as batched variants.
        ///
        /// The same hook is called on both single and batched variants.
        /// For single transfers, the length of the `id` and `amount` arrays are 1.
        function _beforeTokenTransfer(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {}
        /// @dev Override this function to return true if `_afterTokenTransfer` is used.
        /// The is to help the compiler avoid producing dead bytecode.
        function _useAfterTokenTransfer() internal view virtual returns (bool) {
            return false;
        }
        /// @dev Hook that is called after any token transfer.
        /// This includes minting and burning, as well as batched variants.
        ///
        /// The same hook is called on both single and batched variants.
        /// For single transfers, the length of the `id` and `amount` arrays are 1.
        function _afterTokenTransfer(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {}
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      PRIVATE HELPERS                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Helper for calling the `_afterTokenTransfer` hook.
        /// The is to help the compiler avoid producing dead bytecode.
        function _afterTokenTransferCalldata(
            address from,
            address to,
            uint256[] calldata ids,
            uint256[] calldata amounts,
            bytes calldata data
        ) private {
            if (_useAfterTokenTransfer()) {
                _afterTokenTransfer(from, to, ids, amounts, data);
            }
        }
        /// @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 {IERC1155Receiver-onERC1155Received} on `to`.
        /// Reverts if the target does not support the function correctly.
        function _checkOnERC1155Received(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) private {
            /// @solidity memory-safe-assembly
            assembly {
                // Prepare the calldata.
                let m := mload(0x40)
                // `onERC1155Received(address,address,uint256,uint256,bytes)`.
                mstore(m, 0xf23a6e61)
                mstore(add(m, 0x20), caller())
                mstore(add(m, 0x40), shr(96, shl(96, from)))
                mstore(add(m, 0x60), id)
                mstore(add(m, 0x80), amount)
                mstore(add(m, 0xa0), 0xa0)
                let n := mload(data)
                mstore(add(m, 0xc0), n)
                if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) }
                // Revert if the call reverts.
                if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) {
                    if returndatasize() {
                        // Bubble up the revert if the call reverts.
                        returndatacopy(0x00, 0x00, returndatasize())
                        revert(0x00, returndatasize())
                    }
                    mstore(m, 0)
                }
                // Load the returndata and compare it with the function selector.
                if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
                    mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
                    revert(0x1c, 0x04)
                }
            }
        }
        /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`.
        /// Reverts if the target does not support the function correctly.
        function _checkOnERC1155BatchReceived(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) private {
            /// @solidity memory-safe-assembly
            assembly {
                // Prepare the calldata.
                let m := mload(0x40)
                // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
                mstore(m, 0xbc197c81)
                mstore(add(m, 0x20), caller())
                mstore(add(m, 0x40), shr(96, shl(96, from)))
                // Copy the `ids`.
                mstore(add(m, 0x60), 0xa0)
                let n := add(0x20, shl(5, mload(ids)))
                let o := add(m, 0xc0)
                pop(staticcall(gas(), 4, ids, n, o, n))
                // Copy the `amounts`.
                let s := add(0xa0, returndatasize())
                mstore(add(m, 0x80), s)
                o := add(o, returndatasize())
                n := add(0x20, shl(5, mload(amounts)))
                pop(staticcall(gas(), 4, amounts, n, o, n))
                // Copy the `data`.
                mstore(add(m, 0xa0), add(s, returndatasize()))
                o := add(o, returndatasize())
                n := add(0x20, mload(data))
                pop(staticcall(gas(), 4, data, n, o, n))
                n := sub(add(o, returndatasize()), add(m, 0x1c))
                // Revert if the call reverts.
                if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) {
                    if returndatasize() {
                        // Bubble up the revert if the call reverts.
                        returndatacopy(0x00, 0x00, returndatasize())
                        revert(0x00, returndatasize())
                    }
                    mstore(m, 0)
                }
                // Load the returndata and compare it with the function selector.
                if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
                    mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
                    revert(0x1c, 0x04)
                }
            }
        }
        /// @dev Returns `x` in an array with a single element.
        function _single(uint256 x) private pure returns (uint256[] memory result) {
            assembly {
                result := mload(0x40)
                mstore(0x40, add(result, 0x40))
                mstore(result, 1)
                mstore(add(result, 0x20), x)
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;
    import {
        BasicOrderType,
        ItemType,
        OrderType,
        Side
    } from "./ConsiderationEnums.sol";
    import {
        CalldataPointer,
        MemoryPointer
    } from "../helpers/PointerLibraries.sol";
    /**
     * @dev An order contains eleven components: an offerer, a zone (or account that
     *      can cancel the order or restrict who can fulfill the order depending on
     *      the type), the order type (specifying partial fill support as well as
     *      restricted order status), the start and end time, a hash that will be
     *      provided to the zone when validating restricted orders, a salt, a key
     *      corresponding to a given conduit, a counter, and an arbitrary number of
     *      offer items that can be spent along with consideration items that must
     *      be received by their respective recipient.
     */
    struct OrderComponents {
        address offerer;
        address zone;
        OfferItem[] offer;
        ConsiderationItem[] consideration;
        OrderType orderType;
        uint256 startTime;
        uint256 endTime;
        bytes32 zoneHash;
        uint256 salt;
        bytes32 conduitKey;
        uint256 counter;
    }
    /**
     * @dev An offer item has five components: an item type (ETH or other native
     *      tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and
     *      ERC1155), a token address, a dual-purpose "identifierOrCriteria"
     *      component that will either represent a tokenId or a merkle root
     *      depending on the item type, and a start and end amount that support
     *      increasing or decreasing amounts over the duration of the respective
     *      order.
     */
    struct OfferItem {
        ItemType itemType;
        address token;
        uint256 identifierOrCriteria;
        uint256 startAmount;
        uint256 endAmount;
    }
    /**
     * @dev A consideration item has the same five components as an offer item and
     *      an additional sixth component designating the required recipient of the
     *      item.
     */
    struct ConsiderationItem {
        ItemType itemType;
        address token;
        uint256 identifierOrCriteria;
        uint256 startAmount;
        uint256 endAmount;
        address payable recipient;
    }
    /**
     * @dev A spent item is translated from a utilized offer item and has four
     *      components: an item type (ETH or other native tokens, ERC20, ERC721, and
     *      ERC1155), a token address, a tokenId, and an amount.
     */
    struct SpentItem {
        ItemType itemType;
        address token;
        uint256 identifier;
        uint256 amount;
    }
    /**
     * @dev A received item is translated from a utilized consideration item and has
     *      the same four components as a spent item, as well as an additional fifth
     *      component designating the required recipient of the item.
     */
    struct ReceivedItem {
        ItemType itemType;
        address token;
        uint256 identifier;
        uint256 amount;
        address payable recipient;
    }
    /**
     * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155
     *      matching, a group of six functions may be called that only requires a
     *      subset of the usual order arguments. Note the use of a "basicOrderType"
     *      enum; this represents both the usual order type as well as the "route"
     *      of the basic order (a simple derivation function for the basic order
     *      type is `basicOrderType = orderType + (4 * basicOrderRoute)`.)
     */
    struct BasicOrderParameters {
        // calldata offset
        address considerationToken; // 0x24
        uint256 considerationIdentifier; // 0x44
        uint256 considerationAmount; // 0x64
        address payable offerer; // 0x84
        address zone; // 0xa4
        address offerToken; // 0xc4
        uint256 offerIdentifier; // 0xe4
        uint256 offerAmount; // 0x104
        BasicOrderType basicOrderType; // 0x124
        uint256 startTime; // 0x144
        uint256 endTime; // 0x164
        bytes32 zoneHash; // 0x184
        uint256 salt; // 0x1a4
        bytes32 offererConduitKey; // 0x1c4
        bytes32 fulfillerConduitKey; // 0x1e4
        uint256 totalOriginalAdditionalRecipients; // 0x204
        AdditionalRecipient[] additionalRecipients; // 0x224
        bytes signature; // 0x244
        // Total length, excluding dynamic array data: 0x264 (580)
    }
    /**
     * @dev Basic orders can supply any number of additional recipients, with the
     *      implied assumption that they are supplied from the offered ETH (or other
     *      native token) or ERC20 token for the order.
     */
    struct AdditionalRecipient {
        uint256 amount;
        address payable recipient;
    }
    /**
     * @dev The full set of order components, with the exception of the counter,
     *      must be supplied when fulfilling more sophisticated orders or groups of
     *      orders. The total number of original consideration items must also be
     *      supplied, as the caller may specify additional consideration items.
     */
    struct OrderParameters {
        address offerer; // 0x00
        address zone; // 0x20
        OfferItem[] offer; // 0x40
        ConsiderationItem[] consideration; // 0x60
        OrderType orderType; // 0x80
        uint256 startTime; // 0xa0
        uint256 endTime; // 0xc0
        bytes32 zoneHash; // 0xe0
        uint256 salt; // 0x100
        bytes32 conduitKey; // 0x120
        uint256 totalOriginalConsiderationItems; // 0x140
        // offer.length                          // 0x160
    }
    /**
     * @dev Orders require a signature in addition to the other order parameters.
     */
    struct Order {
        OrderParameters parameters;
        bytes signature;
    }
    /**
     * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill)
     *      and a denominator (the total size of the order) in addition to the
     *      signature and other order parameters. It also supports an optional field
     *      for supplying extra data; this data will be provided to the zone if the
     *      order type is restricted and the zone is not the caller, or will be
     *      provided to the offerer as context for contract order types.
     */
    struct AdvancedOrder {
        OrderParameters parameters;
        uint120 numerator;
        uint120 denominator;
        bytes signature;
        bytes extraData;
    }
    /**
     * @dev Orders can be validated (either explicitly via `validate`, or as a
     *      consequence of a full or partial fill), specifically cancelled (they can
     *      also be cancelled in bulk via incrementing a per-zone counter), and
     *      partially or fully filled (with the fraction filled represented by a
     *      numerator and denominator).
     */
    struct OrderStatus {
        bool isValidated;
        bool isCancelled;
        uint120 numerator;
        uint120 denominator;
    }
    /**
     * @dev A criteria resolver specifies an order, side (offer vs. consideration),
     *      and item index. It then provides a chosen identifier (i.e. tokenId)
     *      alongside a merkle proof demonstrating the identifier meets the required
     *      criteria.
     */
    struct CriteriaResolver {
        uint256 orderIndex;
        Side side;
        uint256 index;
        uint256 identifier;
        bytes32[] criteriaProof;
    }
    /**
     * @dev A fulfillment is applied to a group of orders. It decrements a series of
     *      offer and consideration items, then generates a single execution
     *      element. A given fulfillment can be applied to as many offer and
     *      consideration items as desired, but must contain at least one offer and
     *      at least one consideration that match. The fulfillment must also remain
     *      consistent on all key parameters across all offer items (same offerer,
     *      token, type, tokenId, and conduit preference) as well as across all
     *      consideration items (token, type, tokenId, and recipient).
     */
    struct Fulfillment {
        FulfillmentComponent[] offerComponents;
        FulfillmentComponent[] considerationComponents;
    }
    /**
     * @dev Each fulfillment component contains one index referencing a specific
     *      order and another referencing a specific offer or consideration item.
     */
    struct FulfillmentComponent {
        uint256 orderIndex;
        uint256 itemIndex;
    }
    /**
     * @dev An execution is triggered once all consideration items have been zeroed
     *      out. It sends the item in question from the offerer to the item's
     *      recipient, optionally sourcing approvals from either this contract
     *      directly or from the offerer's chosen conduit if one is specified. An
     *      execution is not provided as an argument, but rather is derived via
     *      orders, criteria resolvers, and fulfillments (where the total number of
     *      executions will be less than or equal to the total number of indicated
     *      fulfillments) and returned as part of `matchOrders`.
     */
    struct Execution {
        ReceivedItem item;
        address offerer;
        bytes32 conduitKey;
    }
    /**
     * @dev Restricted orders are validated post-execution by calling validateOrder
     *      on the zone. This struct provides context about the order fulfillment
     *      and any supplied extraData, as well as all order hashes fulfilled in a
     *      call to a match or fulfillAvailable method.
     */
    struct ZoneParameters {
        bytes32 orderHash;
        address fulfiller;
        address offerer;
        SpentItem[] offer;
        ReceivedItem[] consideration;
        bytes extraData;
        bytes32[] orderHashes;
        uint256 startTime;
        uint256 endTime;
        bytes32 zoneHash;
    }
    /**
     * @dev Zones and contract offerers can communicate which schemas they implement
     *      along with any associated metadata related to each schema.
     */
    struct Schema {
        uint256 id;
        bytes metadata;
    }
    using StructPointers for OrderComponents global;
    using StructPointers for OfferItem global;
    using StructPointers for ConsiderationItem global;
    using StructPointers for SpentItem global;
    using StructPointers for ReceivedItem global;
    using StructPointers for BasicOrderParameters global;
    using StructPointers for AdditionalRecipient global;
    using StructPointers for OrderParameters global;
    using StructPointers for Order global;
    using StructPointers for AdvancedOrder global;
    using StructPointers for OrderStatus global;
    using StructPointers for CriteriaResolver global;
    using StructPointers for Fulfillment global;
    using StructPointers for FulfillmentComponent global;
    using StructPointers for Execution global;
    using StructPointers for ZoneParameters global;
    /**
     * @dev This library provides a set of functions for converting structs to
     *      pointers.
     */
    library StructPointers {
        /**
         * @dev Get a MemoryPointer from OrderComponents.
         *
         * @param obj The OrderComponents object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            OrderComponents memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from OrderComponents.
         *
         * @param obj The OrderComponents object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            OrderComponents calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from OfferItem.
         *
         * @param obj The OfferItem object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            OfferItem memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from OfferItem.
         *
         * @param obj The OfferItem object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            OfferItem calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from ConsiderationItem.
         *
         * @param obj The ConsiderationItem object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            ConsiderationItem memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from ConsiderationItem.
         *
         * @param obj The ConsiderationItem object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            ConsiderationItem calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from SpentItem.
         *
         * @param obj The SpentItem object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            SpentItem memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from SpentItem.
         *
         * @param obj The SpentItem object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            SpentItem calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from ReceivedItem.
         *
         * @param obj The ReceivedItem object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            ReceivedItem memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from ReceivedItem.
         *
         * @param obj The ReceivedItem object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            ReceivedItem calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from BasicOrderParameters.
         *
         * @param obj The BasicOrderParameters object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            BasicOrderParameters memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from BasicOrderParameters.
         *
         * @param obj The BasicOrderParameters object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            BasicOrderParameters calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from AdditionalRecipient.
         *
         * @param obj The AdditionalRecipient object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            AdditionalRecipient memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from AdditionalRecipient.
         *
         * @param obj The AdditionalRecipient object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            AdditionalRecipient calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from OrderParameters.
         *
         * @param obj The OrderParameters object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            OrderParameters memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from OrderParameters.
         *
         * @param obj The OrderParameters object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            OrderParameters calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from Order.
         *
         * @param obj The Order object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            Order memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from Order.
         *
         * @param obj The Order object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            Order calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from AdvancedOrder.
         *
         * @param obj The AdvancedOrder object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            AdvancedOrder memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from AdvancedOrder.
         *
         * @param obj The AdvancedOrder object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            AdvancedOrder calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from OrderStatus.
         *
         * @param obj The OrderStatus object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            OrderStatus memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from OrderStatus.
         *
         * @param obj The OrderStatus object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            OrderStatus calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from CriteriaResolver.
         *
         * @param obj The CriteriaResolver object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            CriteriaResolver memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from CriteriaResolver.
         *
         * @param obj The CriteriaResolver object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            CriteriaResolver calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from Fulfillment.
         *
         * @param obj The Fulfillment object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            Fulfillment memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from Fulfillment.
         *
         * @param obj The Fulfillment object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            Fulfillment calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from FulfillmentComponent.
         *
         * @param obj The FulfillmentComponent object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            FulfillmentComponent memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from FulfillmentComponent.
         *
         * @param obj The FulfillmentComponent object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            FulfillmentComponent calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from Execution.
         *
         * @param obj The Execution object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            Execution memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from Execution.
         *
         * @param obj The Execution object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            Execution calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a MemoryPointer from ZoneParameters.
         *
         * @param obj The ZoneParameters object.
         *
         * @return ptr The MemoryPointer.
         */
        function toMemoryPointer(
            ZoneParameters memory obj
        ) internal pure returns (MemoryPointer ptr) {
            assembly {
                ptr := obj
            }
        }
        /**
         * @dev Get a CalldataPointer from ZoneParameters.
         *
         * @param obj The ZoneParameters object.
         *
         * @return ptr The CalldataPointer.
         */
        function toCalldataPointer(
            ZoneParameters calldata obj
        ) internal pure returns (CalldataPointer ptr) {
            assembly {
                ptr := obj
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;
    import {ReceivedItem, Schema, SpentItem} from "../lib/ConsiderationStructs.sol";
    import {IERC165} from "../interfaces/IERC165.sol";
    /**
     * @title ContractOffererInterface
     * @notice Contains the minimum interfaces needed to interact with a contract
     *         offerer.
     */
    interface ContractOffererInterface is IERC165 {
        /**
         * @dev Generates an order with the specified minimum and maximum spent
         *      items, and optional context (supplied as extraData).
         *
         * @param fulfiller       The address of the fulfiller.
         * @param minimumReceived The minimum items that the caller is willing to
         *                        receive.
         * @param maximumSpent    The maximum items the caller is willing to spend.
         * @param context         Additional context of the order.
         *
         * @return offer         A tuple containing the offer items.
         * @return consideration A tuple containing the consideration items.
         */
        function generateOrder(
            address fulfiller,
            SpentItem[] calldata minimumReceived,
            SpentItem[] calldata maximumSpent,
            bytes calldata context // encoded based on the schemaID
        ) external returns (SpentItem[] memory offer, ReceivedItem[] memory consideration);
        /**
         * @dev Ratifies an order with the specified offer, consideration, and
         *      optional context (supplied as extraData).
         *
         * @param offer         The offer items.
         * @param consideration The consideration items.
         * @param context       Additional context of the order.
         * @param orderHashes   The hashes to ratify.
         * @param contractNonce The nonce of the contract.
         *
         * @return ratifyOrderMagicValue The magic value returned by the contract
         *                               offerer.
         */
        function ratifyOrder(
            SpentItem[] calldata offer,
            ReceivedItem[] calldata consideration,
            bytes calldata context, // encoded based on the schemaID
            bytes32[] calldata orderHashes,
            uint256 contractNonce
        ) external returns (bytes4 ratifyOrderMagicValue);
        /**
         * @dev View function to preview an order generated in response to a minimum
         *      set of received items, maximum set of spent items, and context
         *      (supplied as extraData).
         *
         * @param caller          The address of the caller (e.g. Seaport).
         * @param fulfiller       The address of the fulfiller (e.g. the account
         *                        calling Seaport).
         * @param minimumReceived The minimum items that the caller is willing to
         *                        receive.
         * @param maximumSpent    The maximum items the caller is willing to spend.
         * @param context         Additional context of the order.
         *
         * @return offer         A tuple containing the offer items.
         * @return consideration A tuple containing the consideration items.
         */
        function previewOrder(
            address caller,
            address fulfiller,
            SpentItem[] calldata minimumReceived,
            SpentItem[] calldata maximumSpent,
            bytes calldata context // encoded based on the schemaID
        ) external view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration);
        /**
         * @dev Gets the metadata for this contract offerer.
         *
         * @return name    The name of the contract offerer.
         * @return schemas The schemas supported by the contract offerer.
         */
        function getSeaportMetadata() external view returns (string memory name, Schema[] memory schemas); // map to Seaport Improvement Proposal IDs
        function supportsInterface(bytes4 interfaceId) external view override returns (bool);
        // Additional functions and/or events based on implemented schemaIDs
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.19;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    interface ISeaDropTokenContractMetadata {
        /**
         * @dev Emit an event for token metadata reveals/updates,
         *      according to EIP-4906.
         *
         * @param _fromTokenId The start token id.
         * @param _toTokenId   The end token id.
         */
        event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
        /**
         * @dev Emit an event when the URI for the collection-level metadata
         *      is updated.
         */
        event ContractURIUpdated(string newContractURI);
        /**
         * @dev Emit an event with the previous and new provenance hash after
         *      being updated.
         */
        event ProvenanceHashUpdated(bytes32 previousHash, bytes32 newHash);
        /**
         * @dev Emit an event when the EIP-2981 royalty info is updated.
         */
        event RoyaltyInfoUpdated(address receiver, uint256 basisPoints);
        /**
         * @notice Throw if the max supply exceeds uint64, a limit
         *         due to the storage of bit-packed variables.
         */
        error CannotExceedMaxSupplyOfUint64(uint256 got);
        /**
         * @dev Revert with an error when attempting to set the provenance
         *      hash after the mint has started.
         */
        error ProvenanceHashCannotBeSetAfterMintStarted();
        /**
         * @dev Revert with an error when attempting to set the provenance
         *      hash after it has already been set.
         */
        error ProvenanceHashCannotBeSetAfterAlreadyBeingSet();
        /**
         * @notice Sets the base URI for the token metadata and emits an event.
         *
         * @param tokenURI The new base URI to set.
         */
        function setBaseURI(string calldata tokenURI) external;
        /**
         * @notice Sets the contract URI for contract metadata.
         *
         * @param newContractURI The new contract URI.
         */
        function setContractURI(string calldata newContractURI) external;
        /**
         * @notice Sets the provenance hash and emits an event.
         *
         *         The provenance hash is used for random reveals, which
         *         is a hash of the ordered metadata to show it has not been
         *         modified after mint started.
         *
         *         This function will revert after the first item has been minted.
         *
         * @param newProvenanceHash The new provenance hash to set.
         */
        function setProvenanceHash(bytes32 newProvenanceHash) external;
        /**
         * @notice Sets the default royalty information.
         *
         * Requirements:
         *
         * - `receiver` cannot be the zero address.
         * - `feeNumerator` cannot be greater than the fee denominator of
         *   10_000 basis points.
         */
        function setDefaultRoyalty(address receiver, uint96 feeNumerator) external;
        /**
         * @notice Returns the base URI for token metadata.
         */
        function baseURI() external view returns (string memory);
        /**
         * @notice Returns the contract URI.
         */
        function contractURI() external view returns (string memory);
        /**
         * @notice Returns the provenance hash.
         *         The provenance hash is used for random reveals, which
         *         is a hash of the ordered metadata to show it is unmodified
         *         after mint has started.
         */
        function provenanceHash() external view returns (bytes32);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import {
        ISeaDropTokenContractMetadata
    } from "./ISeaDropTokenContractMetadata.sol";
    interface IERC1155ContractMetadata is ISeaDropTokenContractMetadata {
        /**
         * @dev A struct representing the supply info for a token id,
         *      packed into one storage slot.
         *
         * @param maxSupply   The max supply for the token id.
         * @param totalSupply The total token supply for the token id.
         *                    Subtracted when an item is burned.
         * @param totalMinted The total number of tokens minted for the token id.
         */
        struct TokenSupply {
            uint64 maxSupply; // 64/256 bits
            uint64 totalSupply; // 128/256 bits
            uint64 totalMinted; // 192/256 bits
        }
        /**
         * @dev Emit an event when the max token supply for a token id is updated.
         */
        event MaxSupplyUpdated(uint256 tokenId, uint256 newMaxSupply);
        /**
         * @dev Revert with an error if the mint quantity exceeds the max token
         *      supply.
         */
        error MintExceedsMaxSupply(uint256 total, uint256 maxSupply);
        /**
         * @notice Sets the max supply for a token id and emits an event.
         *
         * @param tokenId      The token id to set the max supply for.
         * @param newMaxSupply The new max supply to set.
         */
        function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external;
        /**
         * @notice Returns the name of the token.
         */
        function name() external view returns (string memory);
        /**
         * @notice Returns the symbol of the token.
         */
        function symbol() external view returns (string memory);
        /**
         * @notice Returns the max token supply for a token id.
         */
        function maxSupply(uint256 tokenId) external view returns (uint256);
        /**
         * @notice Returns the total supply for a token id.
         */
        function totalSupply(uint256 tokenId) external view returns (uint256);
        /**
         * @notice Returns the total minted for a token id.
         */
        function totalMinted(uint256 tokenId) external view returns (uint256);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    interface ICreatorToken {
        event TransferValidatorUpdated(address oldValidator, address newValidator);
        function getTransferValidator() external view returns (address validator);
        function getTransferValidationFunction()
            external
            view
            returns (bytes4 functionSignature, bool isViewFunction);
        function setTransferValidator(address validator) external;
    }
    interface ILegacyCreatorToken {
        event TransferValidatorUpdated(address oldValidator, address newValidator);
        function getTransferValidator() external view returns (address validator);
        function setTransferValidator(address validator) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    interface ITransferValidator721 {
        /// @notice Ensure that a transfer has been authorized for a specific tokenId
        function validateTransfer(
            address caller,
            address from,
            address to,
            uint256 tokenId
        ) external view;
    }
    interface ITransferValidator1155 {
        /// @notice Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and reduce the transferable amount remaining
        function validateTransfer(
            address caller,
            address from,
            address to,
            uint256 tokenId,
            uint256 amount
        ) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    import { ICreatorToken } from "../interfaces/ICreatorToken.sol";
    /**
     * @title  TokenTransferValidator
     * @notice Functionality to use a transfer validator.
     */
    abstract contract TokenTransferValidator is ICreatorToken {
        /// @dev Store the transfer validator. The null address means no transfer validator is set.
        address internal _transferValidator;
        /// @notice Revert with an error if the transfer validator is being set to the same address.
        error SameTransferValidator();
        /// @notice Returns the currently active transfer validator.
        ///         The null address means no transfer validator is set.
        function getTransferValidator() external view returns (address) {
            return _transferValidator;
        }
        /// @notice Set the transfer validator.
        ///         The external method that uses this must include access control.
        function _setTransferValidator(address newValidator) internal {
            address oldValidator = _transferValidator;
            if (oldValidator == newValidator) {
                revert SameTransferValidator();
            }
            _transferValidator = newValidator;
            emit TransferValidatorUpdated(oldValidator, newValidator);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    /// @notice Simple ERC2981 NFT Royalty Standard implementation.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol)
    /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol)
    abstract contract ERC2981 {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The royalty fee numerator exceeds the fee denominator.
        error RoyaltyOverflow();
        /// @dev The royalty receiver cannot be the zero address.
        error RoyaltyReceiverIsZeroAddress();
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          STORAGE                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The default royalty info is given by:
        /// ```
        ///     let packed := sload(_ERC2981_MASTER_SLOT_SEED)
        ///     let receiver := shr(96, packed)
        ///     let royaltyFraction := xor(packed, shl(96, receiver))
        /// ```
        ///
        /// The per token royalty info is given by.
        /// ```
        ///     mstore(0x00, tokenId)
        ///     mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
        ///     let packed := sload(keccak256(0x00, 0x40))
        ///     let receiver := shr(96, packed)
        ///     let royaltyFraction := xor(packed, shl(96, receiver))
        /// ```
        uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          ERC2981                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Checks that `_feeDenominator` is non-zero.
        constructor() {
            require(_feeDenominator() != 0, "Fee denominator cannot be zero.");
        }
        /// @dev Returns the denominator for the royalty amount.
        /// Defaults to 10000, which represents fees in basis points.
        /// Override this function to return a custom amount if needed.
        function _feeDenominator() internal pure virtual returns (uint96) {
            return 10000;
        }
        /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
        /// See: https://eips.ethereum.org/EIPS/eip-165
        /// This function call must use less than 30000 gas.
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                let s := shr(224, interfaceId)
                // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a.
                result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a))
            }
        }
        /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`.
        function royaltyInfo(uint256 tokenId, uint256 salePrice)
            public
            view
            virtual
            returns (address receiver, uint256 royaltyAmount)
        {
            uint256 feeDenominator = _feeDenominator();
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x00, tokenId)
                mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                let packed := sload(keccak256(0x00, 0x40))
                receiver := shr(96, packed)
                if iszero(receiver) {
                    packed := sload(mload(0x20))
                    receiver := shr(96, packed)
                }
                let x := salePrice
                let y := xor(packed, shl(96, receiver)) // `feeNumerator`.
                // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
                // Out-of-gas revert. Should not be triggered in practice, but included for safety.
                returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y))))
                royaltyAmount := div(mul(x, y), feeDenominator)
            }
        }
        /// @dev Sets the default royalty `receiver` and `feeNumerator`.
        ///
        /// Requirements:
        /// - `receiver` must not be the zero address.
        /// - `feeNumerator` must not be greater than the fee denominator.
        function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
            uint256 feeDenominator = _feeDenominator();
            /// @solidity memory-safe-assembly
            assembly {
                feeNumerator := shr(160, shl(160, feeNumerator))
                if gt(feeNumerator, feeDenominator) {
                    mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                    revert(0x1c, 0x04)
                }
                let packed := shl(96, receiver)
                if iszero(packed) {
                    mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator))
            }
        }
        /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero.
        function _deleteDefaultRoyalty() internal virtual {
            /// @solidity memory-safe-assembly
            assembly {
                sstore(_ERC2981_MASTER_SLOT_SEED, 0)
            }
        }
        /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`.
        ///
        /// Requirements:
        /// - `receiver` must not be the zero address.
        /// - `feeNumerator` must not be greater than the fee denominator.
        function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
            internal
            virtual
        {
            uint256 feeDenominator = _feeDenominator();
            /// @solidity memory-safe-assembly
            assembly {
                feeNumerator := shr(160, shl(160, feeNumerator))
                if gt(feeNumerator, feeDenominator) {
                    mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                    revert(0x1c, 0x04)
                }
                let packed := shl(96, receiver)
                if iszero(packed) {
                    mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                    revert(0x1c, 0x04)
                }
                mstore(0x00, tokenId)
                mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                sstore(keccak256(0x00, 0x40), or(packed, feeNumerator))
            }
        }
        /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero.
        function _resetTokenRoyalty(uint256 tokenId) internal virtual {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x00, tokenId)
                mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                sstore(keccak256(0x00, 0x40), 0)
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    /// @notice Simple single owner authorization mixin.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
    /// @dev While the ownable portion follows
    /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
    /// the nomenclature for the 2-step ownership handover may be unique to this codebase.
    abstract contract Ownable {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The caller is not authorized to call the function.
        error Unauthorized();
        /// @dev The `newOwner` cannot be the zero address.
        error NewOwnerIsZeroAddress();
        /// @dev The `pendingOwner` does not have a valid handover request.
        error NoHandoverRequest();
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           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: `not(_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.
        uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
        /// 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 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 {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(not(_OWNER_SLOT_NOT), 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 {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := not(_OWNER_SLOT_NOT)
                // 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(not(_OWNER_SLOT_NOT)))) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  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(not(_OWNER_SLOT_NOT))
            }
        }
        /// @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))
            }
        }
        /// @dev Returns how long a two-step ownership handover is valid for in seconds.
        function ownershipHandoverValidFor() public view virtual returns (uint64) {
            return 48 * 3600;
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         MODIFIERS                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Marks a function as only callable by the owner.
        modifier onlyOwner() virtual {
            _checkOwner();
            _;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
    pragma solidity ^0.8.19;
    import "../../utils/AddressUpgradeable.sol";
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```solidity
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     *
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Indicates that the contract has been initialized.
         * @custom:oz-retyped-from bool
         */
        uint8 private _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool private _initializing;
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint8 version);
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts.
         *
         * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
         * constructor.
         *
         * Emits an {Initialized} event.
         */
        modifier initializer() {
            bool isTopLevelCall = !_initializing;
            require(
                (isTopLevelCall && _initialized < 1) || (address(this).code.length == 0 && _initialized == 1),
                "Initializable: contract is already initialized"
            );
            _initialized = 1;
            if (isTopLevelCall) {
                _initializing = true;
            }
            _;
            if (isTopLevelCall) {
                _initializing = false;
                emit Initialized(1);
            }
        }
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
         * are added through upgrades and that require initialization.
         *
         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
         * cannot be nested. If one is invoked in the context of another, execution will revert.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         *
         * WARNING: setting the version to 255 will prevent any future reinitialization.
         *
         * Emits an {Initialized} event.
         */
        modifier reinitializer(uint8 version) {
            require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
            _initialized = version;
            _initializing = true;
            _;
            _initializing = false;
            emit Initialized(version);
        }
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            require(_initializing, "Initializable: contract is not initializing");
            _;
        }
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         *
         * Emits an {Initialized} event the first time it is successfully executed.
         */
        function _disableInitializers() internal virtual {
            require(!_initializing, "Initializable: contract is initializing");
            if (_initialized != type(uint8).max) {
                _initialized = type(uint8).max;
                emit Initialized(type(uint8).max);
            }
        }
        /**
         * @dev Returns the highest version that has been initialized. See {reinitializer}.
         */
        function _getInitializedVersion() internal view returns (uint8) {
            return _initialized;
        }
        /**
         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
         */
        function _isInitializing() internal view returns (bool) {
            return _initializing;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { CreatorPayout, PublicDrop } from "./ERC721SeaDropStructs.sol";
    interface SeaDropErrorsAndEvents {
        /**
         * @notice The SeaDrop token types, emitted as part of
         *         `event SeaDropTokenDeployed`.
         */
        enum SEADROP_TOKEN_TYPE {
            ERC721_STANDARD,
            ERC721_CLONE,
            ERC721_UPGRADEABLE,
            ERC1155_STANDARD,
            ERC1155_CLONE,
            ERC1155_UPGRADEABLE
        }
        /**
         * @notice An event to signify that a SeaDrop token contract was deployed.
         */
        event SeaDropTokenDeployed(SEADROP_TOKEN_TYPE tokenType);
        /**
         * @notice Revert with an error if the function selector is not supported.
         */
        error UnsupportedFunctionSelector(bytes4 selector);
        /**
         * @dev Revert with an error if the drop stage is not active.
         */
        error NotActive(
            uint256 currentTimestamp,
            uint256 startTimestamp,
            uint256 endTimestamp
        );
        /**
         * @dev Revert with an error if the mint quantity exceeds the max allowed
         *      to be minted per wallet.
         */
        error MintQuantityExceedsMaxMintedPerWallet(uint256 total, uint256 allowed);
        /**
         * @dev Revert with an error if the mint quantity exceeds the max token
         *      supply.
         */
        error MintQuantityExceedsMaxSupply(uint256 total, uint256 maxSupply);
        /**
         * @dev Revert with an error if the mint quantity exceeds the max token
         *      supply for the stage.
         *      Note: The `maxTokenSupplyForStage` for public mint is
         *      always `type(uint).max`.
         */
        error MintQuantityExceedsMaxTokenSupplyForStage(
            uint256 total,
            uint256 maxTokenSupplyForStage
        );
        /**
         * @dev Revert if the fee recipient is the zero address.
         */
        error FeeRecipientCannotBeZeroAddress();
        /**
         * @dev Revert if the fee recipient is not already included.
         */
        error FeeRecipientNotPresent();
        /**
         * @dev Revert if the fee basis points is greater than 10_000.
         */
        error InvalidFeeBps(uint256 feeBps);
        /**
         * @dev Revert if the fee recipient is already included.
         */
        error DuplicateFeeRecipient();
        /**
         * @dev Revert if the fee recipient is restricted and not allowed.
         */
        error FeeRecipientNotAllowed(address got);
        /**
         * @dev Revert if the creator payout address is the zero address.
         */
        error CreatorPayoutAddressCannotBeZeroAddress();
        /**
         * @dev Revert if the creator payouts are not set.
         */
        error CreatorPayoutsNotSet();
        /**
         * @dev Revert if the creator payout basis points are zero.
         */
        error CreatorPayoutBasisPointsCannotBeZero();
        /**
         * @dev Revert if the total basis points for the creator payouts
         *      don't equal exactly 10_000.
         */
        error InvalidCreatorPayoutTotalBasisPoints(
            uint256 totalReceivedBasisPoints
        );
        /**
         * @dev Revert if the creator payout basis points don't add up to 10_000.
         */
        error InvalidCreatorPayoutBasisPoints(uint256 totalReceivedBasisPoints);
        /**
         * @dev Revert with an error if the allow list proof is invalid.
         */
        error InvalidProof();
        /**
         * @dev Revert if a supplied signer address is the zero address.
         */
        error SignerCannotBeZeroAddress();
        /**
         * @dev Revert with an error if a signer is not included in
         *      the enumeration when removing.
         */
        error SignerNotPresent();
        /**
         * @dev Revert with an error if a payer is not included in
         *      the enumeration when removing.
         */
        error PayerNotPresent();
        /**
         * @dev Revert with an error if a payer is already included in mapping
         *      when adding.
         */
        error DuplicatePayer();
        /**
         * @dev Revert with an error if a signer is already included in mapping
         *      when adding.
         */
        error DuplicateSigner();
        /**
         * @dev Revert with an error if the payer is not allowed. The minter must
         *      pay for their own mint.
         */
        error PayerNotAllowed(address got);
        /**
         * @dev Revert if a supplied payer address is the zero address.
         */
        error PayerCannotBeZeroAddress();
        /**
         * @dev Revert if the start time is greater than the end time.
         */
        error InvalidStartAndEndTime(uint256 startTime, uint256 endTime);
        /**
         * @dev Revert with an error if the signer payment token is not the same.
         */
        error InvalidSignedPaymentToken(address got, address want);
        /**
         * @dev Revert with an error if supplied signed mint price is less than
         *      the minimum specified.
         */
        error InvalidSignedMintPrice(
            address paymentToken,
            uint256 got,
            uint256 minimum
        );
        /**
         * @dev Revert with an error if supplied signed maxTotalMintableByWallet
         *      is greater than the maximum specified.
         */
        error InvalidSignedMaxTotalMintableByWallet(uint256 got, uint256 maximum);
        /**
         * @dev Revert with an error if supplied signed
         *      maxTotalMintableByWalletPerToken is greater than the maximum
         *      specified.
         */
        error InvalidSignedMaxTotalMintableByWalletPerToken(
            uint256 got,
            uint256 maximum
        );
        /**
         * @dev Revert with an error if the fromTokenId is not within range.
         */
        error InvalidSignedFromTokenId(uint256 got, uint256 minimum);
        /**
         * @dev Revert with an error if the toTokenId is not within range.
         */
        error InvalidSignedToTokenId(uint256 got, uint256 maximum);
        /**
         * @dev Revert with an error if supplied signed start time is less than
         *      the minimum specified.
         */
        error InvalidSignedStartTime(uint256 got, uint256 minimum);
        /**
         * @dev Revert with an error if supplied signed end time is greater than
         *      the maximum specified.
         */
        error InvalidSignedEndTime(uint256 got, uint256 maximum);
        /**
         * @dev Revert with an error if supplied signed maxTokenSupplyForStage
         *      is greater than the maximum specified.
         */
        error InvalidSignedMaxTokenSupplyForStage(uint256 got, uint256 maximum);
        /**
         * @dev Revert with an error if supplied signed feeBps is greater than
         *      the maximum specified, or less than the minimum.
         */
        error InvalidSignedFeeBps(uint256 got, uint256 minimumOrMaximum);
        /**
         * @dev Revert with an error if signed mint did not specify to restrict
         *      fee recipients.
         */
        error SignedMintsMustRestrictFeeRecipients();
        /**
         * @dev Revert with an error if a signature for a signed mint has already
         *      been used.
         */
        error SignatureAlreadyUsed();
        /**
         * @dev Revert with an error if the contract has no balance to withdraw.
         */
        error NoBalanceToWithdraw();
        /**
         * @dev Revert with an error if the caller is not an allowed Seaport.
         */
        error InvalidCallerOnlyAllowedSeaport(address caller);
        /**
         * @dev Revert with an error if the order does not have the ERC1155 magic
         *      consideration item to signify a consecutive mint.
         */
        error MustSpecifyERC1155ConsiderationItemForSeaDropMint();
        /**
         * @dev Revert with an error if the extra data version is not supported.
         */
        error UnsupportedExtraDataVersion(uint8 version);
        /**
         * @dev Revert with an error if the extra data encoding is not supported.
         */
        error InvalidExtraDataEncoding(uint8 version);
        /**
         * @dev Revert with an error if the provided substandard is not supported.
         */
        error InvalidSubstandard(uint8 substandard);
        /**
         * @dev Revert with an error if the implementation contract is called without
         *      delegatecall.
         */
        error OnlyDelegateCalled();
        /**
         * @dev Revert with an error if the provided allowed Seaport is the
         *      zero address.
         */
        error AllowedSeaportCannotBeZeroAddress();
        /**
         * @dev Emit an event when allowed Seaport contracts are updated.
         */
        event AllowedSeaportUpdated(address[] allowedSeaport);
        /**
         * @dev An event with details of a SeaDrop mint, for analytical purposes.
         *
         * @param payer          The address who payed for the tx.
         * @param dropStageIndex The drop stage index. Items minted through
         *                       public mint have dropStageIndex of 0
         */
        event SeaDropMint(address payer, uint256 dropStageIndex);
        /**
         * @dev An event with updated allow list data.
         *
         * @param previousMerkleRoot The previous allow list merkle root.
         * @param newMerkleRoot      The new allow list merkle root.
         * @param publicKeyURI       If the allow list is encrypted, the public key
         *                           URIs that can decrypt the list.
         *                           Empty if unencrypted.
         * @param allowListURI       The URI for the allow list.
         */
        event AllowListUpdated(
            bytes32 indexed previousMerkleRoot,
            bytes32 indexed newMerkleRoot,
            string[] publicKeyURI,
            string allowListURI
        );
        /**
         * @dev An event with updated drop URI.
         */
        event DropURIUpdated(string newDropURI);
        /**
         * @dev An event with the updated creator payout address.
         */
        event CreatorPayoutsUpdated(CreatorPayout[] creatorPayouts);
        /**
         * @dev An event with the updated allowed fee recipient.
         */
        event AllowedFeeRecipientUpdated(
            address indexed feeRecipient,
            bool indexed allowed
        );
        /**
         * @dev An event with the updated signer.
         */
        event SignerUpdated(address indexed signer, bool indexed allowed);
        /**
         * @dev An event with the updated payer.
         */
        event PayerUpdated(address indexed payer, bool indexed allowed);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;
    enum OrderType {
        // 0: no partial fills, anyone can execute
        FULL_OPEN,
        // 1: partial fills supported, anyone can execute
        PARTIAL_OPEN,
        // 2: no partial fills, only offerer or zone can execute
        FULL_RESTRICTED,
        // 3: partial fills supported, only offerer or zone can execute
        PARTIAL_RESTRICTED,
        // 4: contract order type
        CONTRACT
    }
    enum BasicOrderType {
        // 0: no partial fills, anyone can execute
        ETH_TO_ERC721_FULL_OPEN,
        // 1: partial fills supported, anyone can execute
        ETH_TO_ERC721_PARTIAL_OPEN,
        // 2: no partial fills, only offerer or zone can execute
        ETH_TO_ERC721_FULL_RESTRICTED,
        // 3: partial fills supported, only offerer or zone can execute
        ETH_TO_ERC721_PARTIAL_RESTRICTED,
        // 4: no partial fills, anyone can execute
        ETH_TO_ERC1155_FULL_OPEN,
        // 5: partial fills supported, anyone can execute
        ETH_TO_ERC1155_PARTIAL_OPEN,
        // 6: no partial fills, only offerer or zone can execute
        ETH_TO_ERC1155_FULL_RESTRICTED,
        // 7: partial fills supported, only offerer or zone can execute
        ETH_TO_ERC1155_PARTIAL_RESTRICTED,
        // 8: no partial fills, anyone can execute
        ERC20_TO_ERC721_FULL_OPEN,
        // 9: partial fills supported, anyone can execute
        ERC20_TO_ERC721_PARTIAL_OPEN,
        // 10: no partial fills, only offerer or zone can execute
        ERC20_TO_ERC721_FULL_RESTRICTED,
        // 11: partial fills supported, only offerer or zone can execute
        ERC20_TO_ERC721_PARTIAL_RESTRICTED,
        // 12: no partial fills, anyone can execute
        ERC20_TO_ERC1155_FULL_OPEN,
        // 13: partial fills supported, anyone can execute
        ERC20_TO_ERC1155_PARTIAL_OPEN,
        // 14: no partial fills, only offerer or zone can execute
        ERC20_TO_ERC1155_FULL_RESTRICTED,
        // 15: partial fills supported, only offerer or zone can execute
        ERC20_TO_ERC1155_PARTIAL_RESTRICTED,
        // 16: no partial fills, anyone can execute
        ERC721_TO_ERC20_FULL_OPEN,
        // 17: partial fills supported, anyone can execute
        ERC721_TO_ERC20_PARTIAL_OPEN,
        // 18: no partial fills, only offerer or zone can execute
        ERC721_TO_ERC20_FULL_RESTRICTED,
        // 19: partial fills supported, only offerer or zone can execute
        ERC721_TO_ERC20_PARTIAL_RESTRICTED,
        // 20: no partial fills, anyone can execute
        ERC1155_TO_ERC20_FULL_OPEN,
        // 21: partial fills supported, anyone can execute
        ERC1155_TO_ERC20_PARTIAL_OPEN,
        // 22: no partial fills, only offerer or zone can execute
        ERC1155_TO_ERC20_FULL_RESTRICTED,
        // 23: partial fills supported, only offerer or zone can execute
        ERC1155_TO_ERC20_PARTIAL_RESTRICTED
    }
    enum BasicOrderRouteType {
        // 0: provide Ether (or other native token) to receive offered ERC721 item.
        ETH_TO_ERC721,
        // 1: provide Ether (or other native token) to receive offered ERC1155 item.
        ETH_TO_ERC1155,
        // 2: provide ERC20 item to receive offered ERC721 item.
        ERC20_TO_ERC721,
        // 3: provide ERC20 item to receive offered ERC1155 item.
        ERC20_TO_ERC1155,
        // 4: provide ERC721 item to receive offered ERC20 item.
        ERC721_TO_ERC20,
        // 5: provide ERC1155 item to receive offered ERC20 item.
        ERC1155_TO_ERC20
    }
    enum ItemType {
        // 0: ETH on mainnet, MATIC on polygon, etc.
        NATIVE,
        // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work)
        ERC20,
        // 2: ERC721 items
        ERC721,
        // 3: ERC1155 items
        ERC1155,
        // 4: ERC721 items where a number of tokenIds are supported
        ERC721_WITH_CRITERIA,
        // 5: ERC1155 items where a number of ids are supported
        ERC1155_WITH_CRITERIA
    }
    enum Side {
        // 0: Items that can be spent
        OFFER,
        // 1: Items that must be received
        CONSIDERATION
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;
    type CalldataPointer is uint256;
    type ReturndataPointer is uint256;
    type MemoryPointer is uint256;
    using CalldataPointerLib for CalldataPointer global;
    using MemoryPointerLib for MemoryPointer global;
    using ReturndataPointerLib for ReturndataPointer global;
    using CalldataReaders for CalldataPointer global;
    using ReturndataReaders for ReturndataPointer global;
    using MemoryReaders for MemoryPointer global;
    using MemoryWriters for MemoryPointer global;
    CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04);
    MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40);
    uint256 constant IdentityPrecompileAddress = 0x4;
    uint256 constant OffsetOrLengthMask = 0xffffffff;
    uint256 constant _OneWord = 0x20;
    uint256 constant _FreeMemoryPointerSlot = 0x40;
    /// @dev Allocates `size` bytes in memory by increasing the free memory pointer
    ///    and returns the memory pointer to the first byte of the allocated region.
    // (Free functions cannot have visibility.)
    // solhint-disable-next-line func-visibility
    function malloc(uint256 size) pure returns (MemoryPointer mPtr) {
        assembly {
            mPtr := mload(_FreeMemoryPointerSlot)
            mstore(_FreeMemoryPointerSlot, add(mPtr, size))
        }
    }
    // (Free functions cannot have visibility.)
    // solhint-disable-next-line func-visibility
    function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) {
        mPtr = FreeMemoryPPtr.readMemoryPointer();
    }
    // (Free functions cannot have visibility.)
    // solhint-disable-next-line func-visibility
    function setFreeMemoryPointer(MemoryPointer mPtr) pure {
        FreeMemoryPPtr.write(mPtr);
    }
    library CalldataPointerLib {
        function lt(
            CalldataPointer a,
            CalldataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := lt(a, b)
            }
        }
        function gt(
            CalldataPointer a,
            CalldataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := gt(a, b)
            }
        }
        function eq(
            CalldataPointer a,
            CalldataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := eq(a, b)
            }
        }
        function isNull(CalldataPointer a) internal pure returns (bool b) {
            assembly {
                b := iszero(a)
            }
        }
        /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata.
        ///      pointer `cdPtr` must point to some parent object with a dynamic
        ///      type's head stored at `cdPtr + headOffset`.
        function pptr(
            CalldataPointer cdPtr,
            uint256 headOffset
        ) internal pure returns (CalldataPointer cdPtrChild) {
            cdPtrChild = cdPtr.offset(
                cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask
            );
        }
        /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer.
        ///      `cdPtr` must point to some parent object with a dynamic type as its
        ///      first member, e.g. `struct { bytes data; }`
        function pptr(
            CalldataPointer cdPtr
        ) internal pure returns (CalldataPointer cdPtrChild) {
            cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask);
        }
        /// @dev Returns the calldata pointer one word after `cdPtr`.
        function next(
            CalldataPointer cdPtr
        ) internal pure returns (CalldataPointer cdPtrNext) {
            assembly {
                cdPtrNext := add(cdPtr, _OneWord)
            }
        }
        /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`.
        function offset(
            CalldataPointer cdPtr,
            uint256 _offset
        ) internal pure returns (CalldataPointer cdPtrNext) {
            assembly {
                cdPtrNext := add(cdPtr, _offset)
            }
        }
        /// @dev Copies `size` bytes from calldata starting at `src` to memory at
        ///      `dst`.
        function copy(
            CalldataPointer src,
            MemoryPointer dst,
            uint256 size
        ) internal pure {
            assembly {
                calldatacopy(dst, src, size)
            }
        }
    }
    library ReturndataPointerLib {
        function lt(
            ReturndataPointer a,
            ReturndataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := lt(a, b)
            }
        }
        function gt(
            ReturndataPointer a,
            ReturndataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := gt(a, b)
            }
        }
        function eq(
            ReturndataPointer a,
            ReturndataPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := eq(a, b)
            }
        }
        function isNull(ReturndataPointer a) internal pure returns (bool b) {
            assembly {
                b := iszero(a)
            }
        }
        /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata
        ///      pointer. `rdPtr` must point to some parent object with a dynamic
        ///      type's head stored at `rdPtr + headOffset`.
        function pptr(
            ReturndataPointer rdPtr,
            uint256 headOffset
        ) internal pure returns (ReturndataPointer rdPtrChild) {
            rdPtrChild = rdPtr.offset(
                rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask
            );
        }
        /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer.
        ///    `rdPtr` must point to some parent object with a dynamic type as its
        ///    first member, e.g. `struct { bytes data; }`
        function pptr(
            ReturndataPointer rdPtr
        ) internal pure returns (ReturndataPointer rdPtrChild) {
            rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask);
        }
        /// @dev Returns the returndata pointer one word after `cdPtr`.
        function next(
            ReturndataPointer rdPtr
        ) internal pure returns (ReturndataPointer rdPtrNext) {
            assembly {
                rdPtrNext := add(rdPtr, _OneWord)
            }
        }
        /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`.
        function offset(
            ReturndataPointer rdPtr,
            uint256 _offset
        ) internal pure returns (ReturndataPointer rdPtrNext) {
            assembly {
                rdPtrNext := add(rdPtr, _offset)
            }
        }
        /// @dev Copies `size` bytes from returndata starting at `src` to memory at
        /// `dst`.
        function copy(
            ReturndataPointer src,
            MemoryPointer dst,
            uint256 size
        ) internal pure {
            assembly {
                returndatacopy(dst, src, size)
            }
        }
    }
    library MemoryPointerLib {
        function copy(
            MemoryPointer src,
            MemoryPointer dst,
            uint256 size
        ) internal view {
            assembly {
                let success := staticcall(
                    gas(),
                    IdentityPrecompileAddress,
                    src,
                    size,
                    dst,
                    size
                )
                if or(iszero(returndatasize()), iszero(success)) {
                    revert(0, 0)
                }
            }
        }
        function lt(
            MemoryPointer a,
            MemoryPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := lt(a, b)
            }
        }
        function gt(
            MemoryPointer a,
            MemoryPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := gt(a, b)
            }
        }
        function eq(
            MemoryPointer a,
            MemoryPointer b
        ) internal pure returns (bool c) {
            assembly {
                c := eq(a, b)
            }
        }
        function isNull(MemoryPointer a) internal pure returns (bool b) {
            assembly {
                b := iszero(a)
            }
        }
        function hash(
            MemoryPointer ptr,
            uint256 length
        ) internal pure returns (bytes32 _hash) {
            assembly {
                _hash := keccak256(ptr, length)
            }
        }
        /// @dev Returns the memory pointer one word after `mPtr`.
        function next(
            MemoryPointer mPtr
        ) internal pure returns (MemoryPointer mPtrNext) {
            assembly {
                mPtrNext := add(mPtr, _OneWord)
            }
        }
        /// @dev Returns the memory pointer `_offset` bytes after `mPtr`.
        function offset(
            MemoryPointer mPtr,
            uint256 _offset
        ) internal pure returns (MemoryPointer mPtrNext) {
            assembly {
                mPtrNext := add(mPtr, _offset)
            }
        }
        /// @dev Resolves a pointer at `mPtr + headOffset` to a memory
        ///    pointer. `mPtr` must point to some parent object with a dynamic
        ///    type's pointer stored at `mPtr + headOffset`.
        function pptr(
            MemoryPointer mPtr,
            uint256 headOffset
        ) internal pure returns (MemoryPointer mPtrChild) {
            mPtrChild = mPtr.offset(headOffset).readMemoryPointer();
        }
        /// @dev Resolves a pointer stored at `mPtr` to a memory pointer.
        ///    `mPtr` must point to some parent object with a dynamic type as its
        ///    first member, e.g. `struct { bytes data; }`
        function pptr(
            MemoryPointer mPtr
        ) internal pure returns (MemoryPointer mPtrChild) {
            mPtrChild = mPtr.readMemoryPointer();
        }
    }
    library CalldataReaders {
        /// @dev Reads the value at `cdPtr` and applies a mask to return only the
        ///    last 4 bytes.
        function readMaskedUint256(
            CalldataPointer cdPtr
        ) internal pure returns (uint256 value) {
            value = cdPtr.readUint256() & OffsetOrLengthMask;
        }
        /// @dev Reads the bool at `cdPtr` in calldata.
        function readBool(
            CalldataPointer cdPtr
        ) internal pure returns (bool value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the address at `cdPtr` in calldata.
        function readAddress(
            CalldataPointer cdPtr
        ) internal pure returns (address value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes1 at `cdPtr` in calldata.
        function readBytes1(
            CalldataPointer cdPtr
        ) internal pure returns (bytes1 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes2 at `cdPtr` in calldata.
        function readBytes2(
            CalldataPointer cdPtr
        ) internal pure returns (bytes2 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes3 at `cdPtr` in calldata.
        function readBytes3(
            CalldataPointer cdPtr
        ) internal pure returns (bytes3 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes4 at `cdPtr` in calldata.
        function readBytes4(
            CalldataPointer cdPtr
        ) internal pure returns (bytes4 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes5 at `cdPtr` in calldata.
        function readBytes5(
            CalldataPointer cdPtr
        ) internal pure returns (bytes5 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes6 at `cdPtr` in calldata.
        function readBytes6(
            CalldataPointer cdPtr
        ) internal pure returns (bytes6 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes7 at `cdPtr` in calldata.
        function readBytes7(
            CalldataPointer cdPtr
        ) internal pure returns (bytes7 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes8 at `cdPtr` in calldata.
        function readBytes8(
            CalldataPointer cdPtr
        ) internal pure returns (bytes8 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes9 at `cdPtr` in calldata.
        function readBytes9(
            CalldataPointer cdPtr
        ) internal pure returns (bytes9 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes10 at `cdPtr` in calldata.
        function readBytes10(
            CalldataPointer cdPtr
        ) internal pure returns (bytes10 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes11 at `cdPtr` in calldata.
        function readBytes11(
            CalldataPointer cdPtr
        ) internal pure returns (bytes11 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes12 at `cdPtr` in calldata.
        function readBytes12(
            CalldataPointer cdPtr
        ) internal pure returns (bytes12 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes13 at `cdPtr` in calldata.
        function readBytes13(
            CalldataPointer cdPtr
        ) internal pure returns (bytes13 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes14 at `cdPtr` in calldata.
        function readBytes14(
            CalldataPointer cdPtr
        ) internal pure returns (bytes14 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes15 at `cdPtr` in calldata.
        function readBytes15(
            CalldataPointer cdPtr
        ) internal pure returns (bytes15 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes16 at `cdPtr` in calldata.
        function readBytes16(
            CalldataPointer cdPtr
        ) internal pure returns (bytes16 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes17 at `cdPtr` in calldata.
        function readBytes17(
            CalldataPointer cdPtr
        ) internal pure returns (bytes17 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes18 at `cdPtr` in calldata.
        function readBytes18(
            CalldataPointer cdPtr
        ) internal pure returns (bytes18 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes19 at `cdPtr` in calldata.
        function readBytes19(
            CalldataPointer cdPtr
        ) internal pure returns (bytes19 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes20 at `cdPtr` in calldata.
        function readBytes20(
            CalldataPointer cdPtr
        ) internal pure returns (bytes20 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes21 at `cdPtr` in calldata.
        function readBytes21(
            CalldataPointer cdPtr
        ) internal pure returns (bytes21 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes22 at `cdPtr` in calldata.
        function readBytes22(
            CalldataPointer cdPtr
        ) internal pure returns (bytes22 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes23 at `cdPtr` in calldata.
        function readBytes23(
            CalldataPointer cdPtr
        ) internal pure returns (bytes23 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes24 at `cdPtr` in calldata.
        function readBytes24(
            CalldataPointer cdPtr
        ) internal pure returns (bytes24 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes25 at `cdPtr` in calldata.
        function readBytes25(
            CalldataPointer cdPtr
        ) internal pure returns (bytes25 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes26 at `cdPtr` in calldata.
        function readBytes26(
            CalldataPointer cdPtr
        ) internal pure returns (bytes26 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes27 at `cdPtr` in calldata.
        function readBytes27(
            CalldataPointer cdPtr
        ) internal pure returns (bytes27 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes28 at `cdPtr` in calldata.
        function readBytes28(
            CalldataPointer cdPtr
        ) internal pure returns (bytes28 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes29 at `cdPtr` in calldata.
        function readBytes29(
            CalldataPointer cdPtr
        ) internal pure returns (bytes29 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes30 at `cdPtr` in calldata.
        function readBytes30(
            CalldataPointer cdPtr
        ) internal pure returns (bytes30 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes31 at `cdPtr` in calldata.
        function readBytes31(
            CalldataPointer cdPtr
        ) internal pure returns (bytes31 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the bytes32 at `cdPtr` in calldata.
        function readBytes32(
            CalldataPointer cdPtr
        ) internal pure returns (bytes32 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint8 at `cdPtr` in calldata.
        function readUint8(
            CalldataPointer cdPtr
        ) internal pure returns (uint8 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint16 at `cdPtr` in calldata.
        function readUint16(
            CalldataPointer cdPtr
        ) internal pure returns (uint16 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint24 at `cdPtr` in calldata.
        function readUint24(
            CalldataPointer cdPtr
        ) internal pure returns (uint24 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint32 at `cdPtr` in calldata.
        function readUint32(
            CalldataPointer cdPtr
        ) internal pure returns (uint32 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint40 at `cdPtr` in calldata.
        function readUint40(
            CalldataPointer cdPtr
        ) internal pure returns (uint40 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint48 at `cdPtr` in calldata.
        function readUint48(
            CalldataPointer cdPtr
        ) internal pure returns (uint48 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint56 at `cdPtr` in calldata.
        function readUint56(
            CalldataPointer cdPtr
        ) internal pure returns (uint56 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint64 at `cdPtr` in calldata.
        function readUint64(
            CalldataPointer cdPtr
        ) internal pure returns (uint64 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint72 at `cdPtr` in calldata.
        function readUint72(
            CalldataPointer cdPtr
        ) internal pure returns (uint72 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint80 at `cdPtr` in calldata.
        function readUint80(
            CalldataPointer cdPtr
        ) internal pure returns (uint80 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint88 at `cdPtr` in calldata.
        function readUint88(
            CalldataPointer cdPtr
        ) internal pure returns (uint88 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint96 at `cdPtr` in calldata.
        function readUint96(
            CalldataPointer cdPtr
        ) internal pure returns (uint96 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint104 at `cdPtr` in calldata.
        function readUint104(
            CalldataPointer cdPtr
        ) internal pure returns (uint104 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint112 at `cdPtr` in calldata.
        function readUint112(
            CalldataPointer cdPtr
        ) internal pure returns (uint112 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint120 at `cdPtr` in calldata.
        function readUint120(
            CalldataPointer cdPtr
        ) internal pure returns (uint120 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint128 at `cdPtr` in calldata.
        function readUint128(
            CalldataPointer cdPtr
        ) internal pure returns (uint128 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint136 at `cdPtr` in calldata.
        function readUint136(
            CalldataPointer cdPtr
        ) internal pure returns (uint136 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint144 at `cdPtr` in calldata.
        function readUint144(
            CalldataPointer cdPtr
        ) internal pure returns (uint144 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint152 at `cdPtr` in calldata.
        function readUint152(
            CalldataPointer cdPtr
        ) internal pure returns (uint152 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint160 at `cdPtr` in calldata.
        function readUint160(
            CalldataPointer cdPtr
        ) internal pure returns (uint160 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint168 at `cdPtr` in calldata.
        function readUint168(
            CalldataPointer cdPtr
        ) internal pure returns (uint168 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint176 at `cdPtr` in calldata.
        function readUint176(
            CalldataPointer cdPtr
        ) internal pure returns (uint176 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint184 at `cdPtr` in calldata.
        function readUint184(
            CalldataPointer cdPtr
        ) internal pure returns (uint184 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint192 at `cdPtr` in calldata.
        function readUint192(
            CalldataPointer cdPtr
        ) internal pure returns (uint192 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint200 at `cdPtr` in calldata.
        function readUint200(
            CalldataPointer cdPtr
        ) internal pure returns (uint200 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint208 at `cdPtr` in calldata.
        function readUint208(
            CalldataPointer cdPtr
        ) internal pure returns (uint208 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint216 at `cdPtr` in calldata.
        function readUint216(
            CalldataPointer cdPtr
        ) internal pure returns (uint216 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint224 at `cdPtr` in calldata.
        function readUint224(
            CalldataPointer cdPtr
        ) internal pure returns (uint224 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint232 at `cdPtr` in calldata.
        function readUint232(
            CalldataPointer cdPtr
        ) internal pure returns (uint232 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint240 at `cdPtr` in calldata.
        function readUint240(
            CalldataPointer cdPtr
        ) internal pure returns (uint240 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint248 at `cdPtr` in calldata.
        function readUint248(
            CalldataPointer cdPtr
        ) internal pure returns (uint248 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the uint256 at `cdPtr` in calldata.
        function readUint256(
            CalldataPointer cdPtr
        ) internal pure returns (uint256 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int8 at `cdPtr` in calldata.
        function readInt8(
            CalldataPointer cdPtr
        ) internal pure returns (int8 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int16 at `cdPtr` in calldata.
        function readInt16(
            CalldataPointer cdPtr
        ) internal pure returns (int16 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int24 at `cdPtr` in calldata.
        function readInt24(
            CalldataPointer cdPtr
        ) internal pure returns (int24 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int32 at `cdPtr` in calldata.
        function readInt32(
            CalldataPointer cdPtr
        ) internal pure returns (int32 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int40 at `cdPtr` in calldata.
        function readInt40(
            CalldataPointer cdPtr
        ) internal pure returns (int40 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int48 at `cdPtr` in calldata.
        function readInt48(
            CalldataPointer cdPtr
        ) internal pure returns (int48 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int56 at `cdPtr` in calldata.
        function readInt56(
            CalldataPointer cdPtr
        ) internal pure returns (int56 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int64 at `cdPtr` in calldata.
        function readInt64(
            CalldataPointer cdPtr
        ) internal pure returns (int64 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int72 at `cdPtr` in calldata.
        function readInt72(
            CalldataPointer cdPtr
        ) internal pure returns (int72 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int80 at `cdPtr` in calldata.
        function readInt80(
            CalldataPointer cdPtr
        ) internal pure returns (int80 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int88 at `cdPtr` in calldata.
        function readInt88(
            CalldataPointer cdPtr
        ) internal pure returns (int88 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int96 at `cdPtr` in calldata.
        function readInt96(
            CalldataPointer cdPtr
        ) internal pure returns (int96 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int104 at `cdPtr` in calldata.
        function readInt104(
            CalldataPointer cdPtr
        ) internal pure returns (int104 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int112 at `cdPtr` in calldata.
        function readInt112(
            CalldataPointer cdPtr
        ) internal pure returns (int112 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int120 at `cdPtr` in calldata.
        function readInt120(
            CalldataPointer cdPtr
        ) internal pure returns (int120 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int128 at `cdPtr` in calldata.
        function readInt128(
            CalldataPointer cdPtr
        ) internal pure returns (int128 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int136 at `cdPtr` in calldata.
        function readInt136(
            CalldataPointer cdPtr
        ) internal pure returns (int136 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int144 at `cdPtr` in calldata.
        function readInt144(
            CalldataPointer cdPtr
        ) internal pure returns (int144 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int152 at `cdPtr` in calldata.
        function readInt152(
            CalldataPointer cdPtr
        ) internal pure returns (int152 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int160 at `cdPtr` in calldata.
        function readInt160(
            CalldataPointer cdPtr
        ) internal pure returns (int160 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int168 at `cdPtr` in calldata.
        function readInt168(
            CalldataPointer cdPtr
        ) internal pure returns (int168 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int176 at `cdPtr` in calldata.
        function readInt176(
            CalldataPointer cdPtr
        ) internal pure returns (int176 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int184 at `cdPtr` in calldata.
        function readInt184(
            CalldataPointer cdPtr
        ) internal pure returns (int184 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int192 at `cdPtr` in calldata.
        function readInt192(
            CalldataPointer cdPtr
        ) internal pure returns (int192 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int200 at `cdPtr` in calldata.
        function readInt200(
            CalldataPointer cdPtr
        ) internal pure returns (int200 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int208 at `cdPtr` in calldata.
        function readInt208(
            CalldataPointer cdPtr
        ) internal pure returns (int208 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int216 at `cdPtr` in calldata.
        function readInt216(
            CalldataPointer cdPtr
        ) internal pure returns (int216 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int224 at `cdPtr` in calldata.
        function readInt224(
            CalldataPointer cdPtr
        ) internal pure returns (int224 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int232 at `cdPtr` in calldata.
        function readInt232(
            CalldataPointer cdPtr
        ) internal pure returns (int232 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int240 at `cdPtr` in calldata.
        function readInt240(
            CalldataPointer cdPtr
        ) internal pure returns (int240 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int248 at `cdPtr` in calldata.
        function readInt248(
            CalldataPointer cdPtr
        ) internal pure returns (int248 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
        /// @dev Reads the int256 at `cdPtr` in calldata.
        function readInt256(
            CalldataPointer cdPtr
        ) internal pure returns (int256 value) {
            assembly {
                value := calldataload(cdPtr)
            }
        }
    }
    library ReturndataReaders {
        /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes
        function readMaskedUint256(
            ReturndataPointer rdPtr
        ) internal pure returns (uint256 value) {
            value = rdPtr.readUint256() & OffsetOrLengthMask;
        }
        /// @dev Reads the bool at `rdPtr` in returndata.
        function readBool(
            ReturndataPointer rdPtr
        ) internal pure returns (bool value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the address at `rdPtr` in returndata.
        function readAddress(
            ReturndataPointer rdPtr
        ) internal pure returns (address value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes1 at `rdPtr` in returndata.
        function readBytes1(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes1 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes2 at `rdPtr` in returndata.
        function readBytes2(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes2 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes3 at `rdPtr` in returndata.
        function readBytes3(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes3 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes4 at `rdPtr` in returndata.
        function readBytes4(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes4 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes5 at `rdPtr` in returndata.
        function readBytes5(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes5 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes6 at `rdPtr` in returndata.
        function readBytes6(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes6 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes7 at `rdPtr` in returndata.
        function readBytes7(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes7 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes8 at `rdPtr` in returndata.
        function readBytes8(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes8 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes9 at `rdPtr` in returndata.
        function readBytes9(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes9 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes10 at `rdPtr` in returndata.
        function readBytes10(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes10 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes11 at `rdPtr` in returndata.
        function readBytes11(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes11 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes12 at `rdPtr` in returndata.
        function readBytes12(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes12 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes13 at `rdPtr` in returndata.
        function readBytes13(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes13 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes14 at `rdPtr` in returndata.
        function readBytes14(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes14 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes15 at `rdPtr` in returndata.
        function readBytes15(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes15 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes16 at `rdPtr` in returndata.
        function readBytes16(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes16 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes17 at `rdPtr` in returndata.
        function readBytes17(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes17 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes18 at `rdPtr` in returndata.
        function readBytes18(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes18 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes19 at `rdPtr` in returndata.
        function readBytes19(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes19 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes20 at `rdPtr` in returndata.
        function readBytes20(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes20 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes21 at `rdPtr` in returndata.
        function readBytes21(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes21 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes22 at `rdPtr` in returndata.
        function readBytes22(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes22 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes23 at `rdPtr` in returndata.
        function readBytes23(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes23 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes24 at `rdPtr` in returndata.
        function readBytes24(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes24 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes25 at `rdPtr` in returndata.
        function readBytes25(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes25 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes26 at `rdPtr` in returndata.
        function readBytes26(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes26 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes27 at `rdPtr` in returndata.
        function readBytes27(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes27 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes28 at `rdPtr` in returndata.
        function readBytes28(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes28 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes29 at `rdPtr` in returndata.
        function readBytes29(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes29 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes30 at `rdPtr` in returndata.
        function readBytes30(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes30 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes31 at `rdPtr` in returndata.
        function readBytes31(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes31 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the bytes32 at `rdPtr` in returndata.
        function readBytes32(
            ReturndataPointer rdPtr
        ) internal pure returns (bytes32 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint8 at `rdPtr` in returndata.
        function readUint8(
            ReturndataPointer rdPtr
        ) internal pure returns (uint8 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint16 at `rdPtr` in returndata.
        function readUint16(
            ReturndataPointer rdPtr
        ) internal pure returns (uint16 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint24 at `rdPtr` in returndata.
        function readUint24(
            ReturndataPointer rdPtr
        ) internal pure returns (uint24 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint32 at `rdPtr` in returndata.
        function readUint32(
            ReturndataPointer rdPtr
        ) internal pure returns (uint32 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint40 at `rdPtr` in returndata.
        function readUint40(
            ReturndataPointer rdPtr
        ) internal pure returns (uint40 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint48 at `rdPtr` in returndata.
        function readUint48(
            ReturndataPointer rdPtr
        ) internal pure returns (uint48 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint56 at `rdPtr` in returndata.
        function readUint56(
            ReturndataPointer rdPtr
        ) internal pure returns (uint56 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint64 at `rdPtr` in returndata.
        function readUint64(
            ReturndataPointer rdPtr
        ) internal pure returns (uint64 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint72 at `rdPtr` in returndata.
        function readUint72(
            ReturndataPointer rdPtr
        ) internal pure returns (uint72 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint80 at `rdPtr` in returndata.
        function readUint80(
            ReturndataPointer rdPtr
        ) internal pure returns (uint80 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint88 at `rdPtr` in returndata.
        function readUint88(
            ReturndataPointer rdPtr
        ) internal pure returns (uint88 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint96 at `rdPtr` in returndata.
        function readUint96(
            ReturndataPointer rdPtr
        ) internal pure returns (uint96 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint104 at `rdPtr` in returndata.
        function readUint104(
            ReturndataPointer rdPtr
        ) internal pure returns (uint104 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint112 at `rdPtr` in returndata.
        function readUint112(
            ReturndataPointer rdPtr
        ) internal pure returns (uint112 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint120 at `rdPtr` in returndata.
        function readUint120(
            ReturndataPointer rdPtr
        ) internal pure returns (uint120 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint128 at `rdPtr` in returndata.
        function readUint128(
            ReturndataPointer rdPtr
        ) internal pure returns (uint128 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint136 at `rdPtr` in returndata.
        function readUint136(
            ReturndataPointer rdPtr
        ) internal pure returns (uint136 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint144 at `rdPtr` in returndata.
        function readUint144(
            ReturndataPointer rdPtr
        ) internal pure returns (uint144 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint152 at `rdPtr` in returndata.
        function readUint152(
            ReturndataPointer rdPtr
        ) internal pure returns (uint152 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint160 at `rdPtr` in returndata.
        function readUint160(
            ReturndataPointer rdPtr
        ) internal pure returns (uint160 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint168 at `rdPtr` in returndata.
        function readUint168(
            ReturndataPointer rdPtr
        ) internal pure returns (uint168 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint176 at `rdPtr` in returndata.
        function readUint176(
            ReturndataPointer rdPtr
        ) internal pure returns (uint176 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint184 at `rdPtr` in returndata.
        function readUint184(
            ReturndataPointer rdPtr
        ) internal pure returns (uint184 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint192 at `rdPtr` in returndata.
        function readUint192(
            ReturndataPointer rdPtr
        ) internal pure returns (uint192 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint200 at `rdPtr` in returndata.
        function readUint200(
            ReturndataPointer rdPtr
        ) internal pure returns (uint200 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint208 at `rdPtr` in returndata.
        function readUint208(
            ReturndataPointer rdPtr
        ) internal pure returns (uint208 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint216 at `rdPtr` in returndata.
        function readUint216(
            ReturndataPointer rdPtr
        ) internal pure returns (uint216 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint224 at `rdPtr` in returndata.
        function readUint224(
            ReturndataPointer rdPtr
        ) internal pure returns (uint224 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint232 at `rdPtr` in returndata.
        function readUint232(
            ReturndataPointer rdPtr
        ) internal pure returns (uint232 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint240 at `rdPtr` in returndata.
        function readUint240(
            ReturndataPointer rdPtr
        ) internal pure returns (uint240 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint248 at `rdPtr` in returndata.
        function readUint248(
            ReturndataPointer rdPtr
        ) internal pure returns (uint248 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the uint256 at `rdPtr` in returndata.
        function readUint256(
            ReturndataPointer rdPtr
        ) internal pure returns (uint256 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int8 at `rdPtr` in returndata.
        function readInt8(
            ReturndataPointer rdPtr
        ) internal pure returns (int8 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int16 at `rdPtr` in returndata.
        function readInt16(
            ReturndataPointer rdPtr
        ) internal pure returns (int16 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int24 at `rdPtr` in returndata.
        function readInt24(
            ReturndataPointer rdPtr
        ) internal pure returns (int24 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int32 at `rdPtr` in returndata.
        function readInt32(
            ReturndataPointer rdPtr
        ) internal pure returns (int32 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int40 at `rdPtr` in returndata.
        function readInt40(
            ReturndataPointer rdPtr
        ) internal pure returns (int40 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int48 at `rdPtr` in returndata.
        function readInt48(
            ReturndataPointer rdPtr
        ) internal pure returns (int48 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int56 at `rdPtr` in returndata.
        function readInt56(
            ReturndataPointer rdPtr
        ) internal pure returns (int56 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int64 at `rdPtr` in returndata.
        function readInt64(
            ReturndataPointer rdPtr
        ) internal pure returns (int64 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int72 at `rdPtr` in returndata.
        function readInt72(
            ReturndataPointer rdPtr
        ) internal pure returns (int72 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int80 at `rdPtr` in returndata.
        function readInt80(
            ReturndataPointer rdPtr
        ) internal pure returns (int80 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int88 at `rdPtr` in returndata.
        function readInt88(
            ReturndataPointer rdPtr
        ) internal pure returns (int88 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int96 at `rdPtr` in returndata.
        function readInt96(
            ReturndataPointer rdPtr
        ) internal pure returns (int96 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int104 at `rdPtr` in returndata.
        function readInt104(
            ReturndataPointer rdPtr
        ) internal pure returns (int104 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int112 at `rdPtr` in returndata.
        function readInt112(
            ReturndataPointer rdPtr
        ) internal pure returns (int112 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int120 at `rdPtr` in returndata.
        function readInt120(
            ReturndataPointer rdPtr
        ) internal pure returns (int120 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int128 at `rdPtr` in returndata.
        function readInt128(
            ReturndataPointer rdPtr
        ) internal pure returns (int128 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int136 at `rdPtr` in returndata.
        function readInt136(
            ReturndataPointer rdPtr
        ) internal pure returns (int136 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int144 at `rdPtr` in returndata.
        function readInt144(
            ReturndataPointer rdPtr
        ) internal pure returns (int144 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int152 at `rdPtr` in returndata.
        function readInt152(
            ReturndataPointer rdPtr
        ) internal pure returns (int152 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int160 at `rdPtr` in returndata.
        function readInt160(
            ReturndataPointer rdPtr
        ) internal pure returns (int160 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int168 at `rdPtr` in returndata.
        function readInt168(
            ReturndataPointer rdPtr
        ) internal pure returns (int168 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int176 at `rdPtr` in returndata.
        function readInt176(
            ReturndataPointer rdPtr
        ) internal pure returns (int176 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int184 at `rdPtr` in returndata.
        function readInt184(
            ReturndataPointer rdPtr
        ) internal pure returns (int184 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int192 at `rdPtr` in returndata.
        function readInt192(
            ReturndataPointer rdPtr
        ) internal pure returns (int192 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int200 at `rdPtr` in returndata.
        function readInt200(
            ReturndataPointer rdPtr
        ) internal pure returns (int200 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int208 at `rdPtr` in returndata.
        function readInt208(
            ReturndataPointer rdPtr
        ) internal pure returns (int208 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int216 at `rdPtr` in returndata.
        function readInt216(
            ReturndataPointer rdPtr
        ) internal pure returns (int216 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int224 at `rdPtr` in returndata.
        function readInt224(
            ReturndataPointer rdPtr
        ) internal pure returns (int224 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int232 at `rdPtr` in returndata.
        function readInt232(
            ReturndataPointer rdPtr
        ) internal pure returns (int232 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int240 at `rdPtr` in returndata.
        function readInt240(
            ReturndataPointer rdPtr
        ) internal pure returns (int240 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int248 at `rdPtr` in returndata.
        function readInt248(
            ReturndataPointer rdPtr
        ) internal pure returns (int248 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
        /// @dev Reads the int256 at `rdPtr` in returndata.
        function readInt256(
            ReturndataPointer rdPtr
        ) internal pure returns (int256 value) {
            assembly {
                returndatacopy(0, rdPtr, _OneWord)
                value := mload(0)
            }
        }
    }
    library MemoryReaders {
        /// @dev Reads the memory pointer at `mPtr` in memory.
        function readMemoryPointer(
            MemoryPointer mPtr
        ) internal pure returns (MemoryPointer value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes
        function readMaskedUint256(
            MemoryPointer mPtr
        ) internal pure returns (uint256 value) {
            value = mPtr.readUint256() & OffsetOrLengthMask;
        }
        /// @dev Reads the bool at `mPtr` in memory.
        function readBool(MemoryPointer mPtr) internal pure returns (bool value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the address at `mPtr` in memory.
        function readAddress(
            MemoryPointer mPtr
        ) internal pure returns (address value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes1 at `mPtr` in memory.
        function readBytes1(
            MemoryPointer mPtr
        ) internal pure returns (bytes1 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes2 at `mPtr` in memory.
        function readBytes2(
            MemoryPointer mPtr
        ) internal pure returns (bytes2 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes3 at `mPtr` in memory.
        function readBytes3(
            MemoryPointer mPtr
        ) internal pure returns (bytes3 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes4 at `mPtr` in memory.
        function readBytes4(
            MemoryPointer mPtr
        ) internal pure returns (bytes4 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes5 at `mPtr` in memory.
        function readBytes5(
            MemoryPointer mPtr
        ) internal pure returns (bytes5 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes6 at `mPtr` in memory.
        function readBytes6(
            MemoryPointer mPtr
        ) internal pure returns (bytes6 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes7 at `mPtr` in memory.
        function readBytes7(
            MemoryPointer mPtr
        ) internal pure returns (bytes7 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes8 at `mPtr` in memory.
        function readBytes8(
            MemoryPointer mPtr
        ) internal pure returns (bytes8 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes9 at `mPtr` in memory.
        function readBytes9(
            MemoryPointer mPtr
        ) internal pure returns (bytes9 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes10 at `mPtr` in memory.
        function readBytes10(
            MemoryPointer mPtr
        ) internal pure returns (bytes10 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes11 at `mPtr` in memory.
        function readBytes11(
            MemoryPointer mPtr
        ) internal pure returns (bytes11 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes12 at `mPtr` in memory.
        function readBytes12(
            MemoryPointer mPtr
        ) internal pure returns (bytes12 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes13 at `mPtr` in memory.
        function readBytes13(
            MemoryPointer mPtr
        ) internal pure returns (bytes13 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes14 at `mPtr` in memory.
        function readBytes14(
            MemoryPointer mPtr
        ) internal pure returns (bytes14 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes15 at `mPtr` in memory.
        function readBytes15(
            MemoryPointer mPtr
        ) internal pure returns (bytes15 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes16 at `mPtr` in memory.
        function readBytes16(
            MemoryPointer mPtr
        ) internal pure returns (bytes16 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes17 at `mPtr` in memory.
        function readBytes17(
            MemoryPointer mPtr
        ) internal pure returns (bytes17 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes18 at `mPtr` in memory.
        function readBytes18(
            MemoryPointer mPtr
        ) internal pure returns (bytes18 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes19 at `mPtr` in memory.
        function readBytes19(
            MemoryPointer mPtr
        ) internal pure returns (bytes19 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes20 at `mPtr` in memory.
        function readBytes20(
            MemoryPointer mPtr
        ) internal pure returns (bytes20 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes21 at `mPtr` in memory.
        function readBytes21(
            MemoryPointer mPtr
        ) internal pure returns (bytes21 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes22 at `mPtr` in memory.
        function readBytes22(
            MemoryPointer mPtr
        ) internal pure returns (bytes22 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes23 at `mPtr` in memory.
        function readBytes23(
            MemoryPointer mPtr
        ) internal pure returns (bytes23 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes24 at `mPtr` in memory.
        function readBytes24(
            MemoryPointer mPtr
        ) internal pure returns (bytes24 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes25 at `mPtr` in memory.
        function readBytes25(
            MemoryPointer mPtr
        ) internal pure returns (bytes25 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes26 at `mPtr` in memory.
        function readBytes26(
            MemoryPointer mPtr
        ) internal pure returns (bytes26 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes27 at `mPtr` in memory.
        function readBytes27(
            MemoryPointer mPtr
        ) internal pure returns (bytes27 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes28 at `mPtr` in memory.
        function readBytes28(
            MemoryPointer mPtr
        ) internal pure returns (bytes28 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes29 at `mPtr` in memory.
        function readBytes29(
            MemoryPointer mPtr
        ) internal pure returns (bytes29 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes30 at `mPtr` in memory.
        function readBytes30(
            MemoryPointer mPtr
        ) internal pure returns (bytes30 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes31 at `mPtr` in memory.
        function readBytes31(
            MemoryPointer mPtr
        ) internal pure returns (bytes31 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the bytes32 at `mPtr` in memory.
        function readBytes32(
            MemoryPointer mPtr
        ) internal pure returns (bytes32 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint8 at `mPtr` in memory.
        function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint16 at `mPtr` in memory.
        function readUint16(
            MemoryPointer mPtr
        ) internal pure returns (uint16 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint24 at `mPtr` in memory.
        function readUint24(
            MemoryPointer mPtr
        ) internal pure returns (uint24 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint32 at `mPtr` in memory.
        function readUint32(
            MemoryPointer mPtr
        ) internal pure returns (uint32 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint40 at `mPtr` in memory.
        function readUint40(
            MemoryPointer mPtr
        ) internal pure returns (uint40 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint48 at `mPtr` in memory.
        function readUint48(
            MemoryPointer mPtr
        ) internal pure returns (uint48 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint56 at `mPtr` in memory.
        function readUint56(
            MemoryPointer mPtr
        ) internal pure returns (uint56 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint64 at `mPtr` in memory.
        function readUint64(
            MemoryPointer mPtr
        ) internal pure returns (uint64 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint72 at `mPtr` in memory.
        function readUint72(
            MemoryPointer mPtr
        ) internal pure returns (uint72 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint80 at `mPtr` in memory.
        function readUint80(
            MemoryPointer mPtr
        ) internal pure returns (uint80 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint88 at `mPtr` in memory.
        function readUint88(
            MemoryPointer mPtr
        ) internal pure returns (uint88 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint96 at `mPtr` in memory.
        function readUint96(
            MemoryPointer mPtr
        ) internal pure returns (uint96 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint104 at `mPtr` in memory.
        function readUint104(
            MemoryPointer mPtr
        ) internal pure returns (uint104 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint112 at `mPtr` in memory.
        function readUint112(
            MemoryPointer mPtr
        ) internal pure returns (uint112 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint120 at `mPtr` in memory.
        function readUint120(
            MemoryPointer mPtr
        ) internal pure returns (uint120 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint128 at `mPtr` in memory.
        function readUint128(
            MemoryPointer mPtr
        ) internal pure returns (uint128 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint136 at `mPtr` in memory.
        function readUint136(
            MemoryPointer mPtr
        ) internal pure returns (uint136 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint144 at `mPtr` in memory.
        function readUint144(
            MemoryPointer mPtr
        ) internal pure returns (uint144 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint152 at `mPtr` in memory.
        function readUint152(
            MemoryPointer mPtr
        ) internal pure returns (uint152 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint160 at `mPtr` in memory.
        function readUint160(
            MemoryPointer mPtr
        ) internal pure returns (uint160 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint168 at `mPtr` in memory.
        function readUint168(
            MemoryPointer mPtr
        ) internal pure returns (uint168 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint176 at `mPtr` in memory.
        function readUint176(
            MemoryPointer mPtr
        ) internal pure returns (uint176 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint184 at `mPtr` in memory.
        function readUint184(
            MemoryPointer mPtr
        ) internal pure returns (uint184 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint192 at `mPtr` in memory.
        function readUint192(
            MemoryPointer mPtr
        ) internal pure returns (uint192 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint200 at `mPtr` in memory.
        function readUint200(
            MemoryPointer mPtr
        ) internal pure returns (uint200 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint208 at `mPtr` in memory.
        function readUint208(
            MemoryPointer mPtr
        ) internal pure returns (uint208 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint216 at `mPtr` in memory.
        function readUint216(
            MemoryPointer mPtr
        ) internal pure returns (uint216 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint224 at `mPtr` in memory.
        function readUint224(
            MemoryPointer mPtr
        ) internal pure returns (uint224 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint232 at `mPtr` in memory.
        function readUint232(
            MemoryPointer mPtr
        ) internal pure returns (uint232 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint240 at `mPtr` in memory.
        function readUint240(
            MemoryPointer mPtr
        ) internal pure returns (uint240 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint248 at `mPtr` in memory.
        function readUint248(
            MemoryPointer mPtr
        ) internal pure returns (uint248 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the uint256 at `mPtr` in memory.
        function readUint256(
            MemoryPointer mPtr
        ) internal pure returns (uint256 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int8 at `mPtr` in memory.
        function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int16 at `mPtr` in memory.
        function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int24 at `mPtr` in memory.
        function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int32 at `mPtr` in memory.
        function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int40 at `mPtr` in memory.
        function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int48 at `mPtr` in memory.
        function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int56 at `mPtr` in memory.
        function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int64 at `mPtr` in memory.
        function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int72 at `mPtr` in memory.
        function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int80 at `mPtr` in memory.
        function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int88 at `mPtr` in memory.
        function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int96 at `mPtr` in memory.
        function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int104 at `mPtr` in memory.
        function readInt104(
            MemoryPointer mPtr
        ) internal pure returns (int104 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int112 at `mPtr` in memory.
        function readInt112(
            MemoryPointer mPtr
        ) internal pure returns (int112 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int120 at `mPtr` in memory.
        function readInt120(
            MemoryPointer mPtr
        ) internal pure returns (int120 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int128 at `mPtr` in memory.
        function readInt128(
            MemoryPointer mPtr
        ) internal pure returns (int128 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int136 at `mPtr` in memory.
        function readInt136(
            MemoryPointer mPtr
        ) internal pure returns (int136 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int144 at `mPtr` in memory.
        function readInt144(
            MemoryPointer mPtr
        ) internal pure returns (int144 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int152 at `mPtr` in memory.
        function readInt152(
            MemoryPointer mPtr
        ) internal pure returns (int152 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int160 at `mPtr` in memory.
        function readInt160(
            MemoryPointer mPtr
        ) internal pure returns (int160 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int168 at `mPtr` in memory.
        function readInt168(
            MemoryPointer mPtr
        ) internal pure returns (int168 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int176 at `mPtr` in memory.
        function readInt176(
            MemoryPointer mPtr
        ) internal pure returns (int176 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int184 at `mPtr` in memory.
        function readInt184(
            MemoryPointer mPtr
        ) internal pure returns (int184 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int192 at `mPtr` in memory.
        function readInt192(
            MemoryPointer mPtr
        ) internal pure returns (int192 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int200 at `mPtr` in memory.
        function readInt200(
            MemoryPointer mPtr
        ) internal pure returns (int200 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int208 at `mPtr` in memory.
        function readInt208(
            MemoryPointer mPtr
        ) internal pure returns (int208 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int216 at `mPtr` in memory.
        function readInt216(
            MemoryPointer mPtr
        ) internal pure returns (int216 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int224 at `mPtr` in memory.
        function readInt224(
            MemoryPointer mPtr
        ) internal pure returns (int224 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int232 at `mPtr` in memory.
        function readInt232(
            MemoryPointer mPtr
        ) internal pure returns (int232 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int240 at `mPtr` in memory.
        function readInt240(
            MemoryPointer mPtr
        ) internal pure returns (int240 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int248 at `mPtr` in memory.
        function readInt248(
            MemoryPointer mPtr
        ) internal pure returns (int248 value) {
            assembly {
                value := mload(mPtr)
            }
        }
        /// @dev Reads the int256 at `mPtr` in memory.
        function readInt256(
            MemoryPointer mPtr
        ) internal pure returns (int256 value) {
            assembly {
                value := mload(mPtr)
            }
        }
    }
    library MemoryWriters {
        /// @dev Writes `valuePtr` to memory at `mPtr`.
        function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure {
            assembly {
                mstore(mPtr, valuePtr)
            }
        }
        /// @dev Writes a boolean `value` to `mPtr` in memory.
        function write(MemoryPointer mPtr, bool value) internal pure {
            assembly {
                mstore(mPtr, value)
            }
        }
        /// @dev Writes an address `value` to `mPtr` in memory.
        function write(MemoryPointer mPtr, address value) internal pure {
            assembly {
                mstore(mPtr, value)
            }
        }
        /// @dev Writes a bytes32 `value` to `mPtr` in memory.
        /// Separate name to disambiguate literal write parameters.
        function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure {
            assembly {
                mstore(mPtr, value)
            }
        }
        /// @dev Writes a uint256 `value` to `mPtr` in memory.
        function write(MemoryPointer mPtr, uint256 value) internal pure {
            assembly {
                mstore(mPtr, value)
            }
        }
        /// @dev Writes an int256 `value` to `mPtr` in memory.
        /// Separate name to disambiguate literal write parameters.
        function writeInt(MemoryPointer mPtr, int256 value) internal pure {
            assembly {
                mstore(mPtr, value)
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.7;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
    pragma solidity ^0.8.19;
    /**
     * @dev Collection of functions related to the address type
     */
    library AddressUpgradeable {
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
         *
         * _Available since v4.8._
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            if (success) {
                if (returndata.length == 0) {
                    // only check if target is a contract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    require(target.code.length > 0, "Address: call to non-contract");
                }
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        /**
         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason or using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        function _revert(bytes memory returndata, string memory errorMessage) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol";
    /**
     * @notice A struct defining public drop data.
     *         Designed to fit efficiently in two storage slots.
     *
     * @param startPrice               The start price per token. (Up to 1.2m
     *                                 of native token, e.g. ETH, MATIC)
     * @param endPrice                 The end price per token. If this differs
     *                                 from startPrice, the current price will
     *                                 be calculated based on the current time.
     * @param startTime                The start time, ensure this is not zero.
     * @param endTime                  The end time, ensure this is not zero.
     * @param paymentToken             The payment token address. Null for
     *                                 native token.
     * @param maxTotalMintableByWallet Maximum total number of mints a user is
     *                                 allowed. (The limit for this field is
     *                                 2^16 - 1)
     * @param feeBps                   Fee out of 10_000 basis points to be
     *                                 collected.
     * @param restrictFeeRecipients    If false, allow any fee recipient;
     *                                 if true, check fee recipient is allowed.
     */
    struct PublicDrop {
        uint80 startPrice; // 80/512 bits
        uint80 endPrice; // 160/512 bits
        uint40 startTime; // 200/512 bits
        uint40 endTime; // 240/512 bits
        address paymentToken; // 400/512 bits
        uint16 maxTotalMintableByWallet; // 416/512 bits
        uint16 feeBps; // 432/512 bits
        bool restrictFeeRecipients; // 440/512 bits
    }
    /**
     * @notice A struct defining mint params for an allow list.
     *         An allow list leaf will be composed of `msg.sender` and
     *         the following params.
     *
     *         Note: Since feeBps is encoded in the leaf, backend should ensure
     *         that feeBps is acceptable before generating a proof.
     *
     * @param startPrice               The start price per token. (Up to 1.2m
     *                                 of native token, e.g. ETH, MATIC)
     * @param endPrice                 The end price per token. If this differs
     *                                 from startPrice, the current price will
     *                                 be calculated based on the current time.
     * @param startTime                The start time, ensure this is not zero.
     * @param endTime                  The end time, ensure this is not zero.
     * @param paymentToken             The payment token for the mint. Null for
     *                                 native token.
     * @param maxTotalMintableByWallet Maximum total number of mints a user is
     *                                 allowed.
     * @param maxTokenSupplyForStage   The limit of token supply this stage can
     *                                 mint within.
     * @param dropStageIndex           The drop stage index to emit with the event
     *                                 for analytical purposes. This should be
     *                                 non-zero since the public mint emits with
     *                                 index zero.
     * @param feeBps                   Fee out of 10_000 basis points to be
     *                                 collected.
     * @param restrictFeeRecipients    If false, allow any fee recipient;
     *                                 if true, check fee recipient is allowed.
     */
    struct MintParams {
        uint256 startPrice;
        uint256 endPrice;
        uint256 startTime;
        uint256 endTime;
        address paymentToken;
        uint256 maxTotalMintableByWallet;
        uint256 maxTokenSupplyForStage;
        uint256 dropStageIndex; // non-zero
        uint256 feeBps;
        bool restrictFeeRecipients;
    }
    /**
     * @dev Struct containing internal SeaDrop implementation logic
     *      mint details to avoid stack too deep.
     *
     * @param feeRecipient The fee recipient.
     * @param payer        The payer of the mint.
     * @param minter       The mint recipient.
     * @param quantity     The number of tokens to mint.
     * @param withEffects  Whether to apply state changes of the mint.
     */
    struct MintDetails {
        address feeRecipient;
        address payer;
        address minter;
        uint256 quantity;
        bool withEffects;
    }
    /**
     * @notice A struct to configure multiple contract options in one transaction.
     */
    struct MultiConfigureStruct {
        uint256 maxSupply;
        string baseURI;
        string contractURI;
        PublicDrop publicDrop;
        string dropURI;
        AllowListData allowListData;
        CreatorPayout[] creatorPayouts;
        bytes32 provenanceHash;
        address[] allowedFeeRecipients;
        address[] disallowedFeeRecipients;
        address[] allowedPayers;
        address[] disallowedPayers;
        // Server-signed
        address[] allowedSigners;
        address[] disallowedSigners;
        // ERC-2981
        address royaltyReceiver;
        uint96 royaltyBps;
        // Mint
        address mintRecipient;
        uint256 mintQuantity;
    }