ETH Price: $1,877.19 (-1.76%)

Transaction Decoder

Block:
21457025 at Dec-22-2024 09:04:35 AM +UTC
Transaction Fee:
0.00062664000682678 ETH $1.18
Gas Used:
130,787 Gas / 4.79130194 Gwei

Emitted Events:

216 Seaport.OrderFulfilled( orderHash=6B953979F4EA0DF65F0DB39EC2BBCDD426633BF2451C7932C6A8136DF22EE449, offerer=0xe3a8354d978d5e0fb846c3d5ddaed520ffc8903c, zone=0x004C0050...C00560C00, recipient=[Sender] 0x64b5b5398c8c90a726036337ea58a474094ee59a, offer=, consideration= )
217 SPCHRON.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x000000000000000000000000e3a8354d978d5e0fb846c3d5ddaed520ffc8903c, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000001d01 )
218 SPCHRON.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000e3a8354d978d5e0fb846c3d5ddaed520ffc8903c, 0x00000000000000000000000064b5b5398c8c90a726036337ea58a474094ee59a, 0x0000000000000000000000000000000000000000000000000000000000001d01 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...1123eB395
(Seaport 1.6)
0x0000a26b...000fAa719
267.65712559061716582 Eth267.65885059061716582 Eth0.001725
(Titan Builder)
8.847245340040210985 Eth8.847246145688130985 Eth0.00000080564792
0x64B5b539...4094ee59a
0.075389594179680738 Eth
Nonce: 10
0.005762954172853958 Eth
Nonce: 11
0.06962664000682678
0xbf257534...5fad8ee8d
0xe3A8354D...0FfC8903c 1.056750121611145439 Eth1.124025121611145439 Eth0.067275

Execution Trace

ETH 0.069 Seaport.fulfillBasicOrder( [{name:considerationToken, type:address, order:1, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:considerationIdentifier, type:uint256, order:2, indexed:false, value:0, valueString:0}, {name:considerationAmount, type:uint256, order:3, indexed:false, value:67275000000000000, valueString:67275000000000000}, {name:offerer, type:address, order:4, indexed:false, value:0xe3A8354D978d5E0FB846c3d5ddaED520FfC8903c, valueString:0xe3A8354D978d5E0FB846c3d5ddaED520FfC8903c}, {name:zone, type:address, order:5, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {name:offerToken, type:address, order:6, indexed:false, value:0xbf2575341e0882Bbf6CA8769F39eE435fad8ee8d, valueString:0xbf2575341e0882Bbf6CA8769F39eE435fad8ee8d}, {name:offerIdentifier, type:uint256, order:7, indexed:false, value:7425, valueString:7425}, {name:offerAmount, type:uint256, order:8, indexed:false, value:1, valueString:1}, {name:basicOrderType, type:uint8, order:9, indexed:false, value:0, valueString:0}, {name:startTime, type:uint256, order:10, indexed:false, value:1734848198, valueString:1734848198}, {name:endTime, type:uint256, order:11, indexed:false, value:1734934597, valueString:1734934597}, {name:zoneHash, type:bytes32, order:12, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:13, indexed:false, value:24446860302761739304752683030156737591518664810215442929800590828272268215094, valueString:24446860302761739304752683030156737591518664810215442929800590828272268215094}, {name:offererConduitKey, type:bytes32, order:14, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:fulfillerConduitKey, type:bytes32, order:15, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalAdditionalRecipients, type:uint256, order:16, indexed:false, value:1, valueString:1}, {name:additionalRecipients, type:tuple[], order:17, indexed:false}, {name:signature, type:bytes, order:18, indexed:false, value:0x18221B2C8E833711279D70027047F8340DE902AC65DE4EFFE09B0CE529C5825CBE2C2012138E11E2DFEDBA63C3B8170290482B3DCA13BF44C2E0E30E8D40B034, valueString:0x18221B2C8E833711279D70027047F8340DE902AC65DE4EFFE09B0CE529C5825CBE2C2012138E11E2DFEDBA63C3B8170290482B3DCA13BF44C2E0E30E8D40B034}] ) => ( fulfilled=True )
  • Null: 0x000...001.77104b30( )
  • Conduit.execute( transfers= ) => ( transfers= )
    • SPCHRON.23b872dd( )
      • ERC721CreatorImplementation.transferFrom( from=0xe3A8354D978d5E0FB846c3d5ddaED520FfC8903c, to=0x64B5b5398C8c90a726036337EA58A474094ee59a, tokenId=7425 )
      • ETH 0.001725 PayableProxy.CALL( )
      • ETH 0.067275 0xe3a8354d978d5e0fb846c3d5ddaed520ffc8903c.CALL( )
        File 1 of 5: Seaport
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import { Consideration } from "./lib/Consideration.sol";
        /**
         * @title Seaport
         * @custom:version 1.6
         * @author 0age (0age.eth)
         * @custom:coauthor d1ll0n (d1ll0n.eth)
         * @custom:coauthor transmissions11 (t11s.eth)
         * @custom:coauthor James Wenzel (emo.eth)
         * @custom:coauthor Daniel Viau (snotrocket.eth)
         * @custom:contributor Kartik (slokh.eth)
         * @custom:contributor LeFevre (lefevre.eth)
         * @custom:contributor Joseph Schiarizzi (CupOJoseph.eth)
         * @custom:contributor Aspyn Palatnick (stuckinaboot.eth)
         * @custom:contributor Stephan Min (stephanm.eth)
         * @custom:contributor Ryan Ghods (ralxz.eth)
         * @custom:contributor hack3r-0m (hack3r-0m.eth)
         * @custom:contributor Diego Estevez (antidiego.eth)
         * @custom:contributor Chomtana (chomtana.eth)
         * @custom:contributor Saw-mon and Natalie (sawmonandnatalie.eth)
         * @custom:contributor 0xBeans (0xBeans.eth)
         * @custom:contributor 0x4non (punkdev.eth)
         * @custom:contributor Laurence E. Day (norsefire.eth)
         * @custom:contributor vectorized.eth (vectorized.eth)
         * @custom:contributor karmacoma (karmacoma.eth)
         * @custom:contributor horsefacts (horsefacts.eth)
         * @custom:contributor UncarvedBlock (uncarvedblock.eth)
         * @custom:contributor Zoraiz Mahmood (zorz.eth)
         * @custom:contributor William Poulin (wpoulin.eth)
         * @custom:contributor Rajiv Patel-O'Connor (rajivpoc.eth)
         * @custom:contributor tserg (tserg.eth)
         * @custom:contributor cygaar (cygaar.eth)
         * @custom:contributor Meta0xNull (meta0xnull.eth)
         * @custom:contributor gpersoon (gpersoon.eth)
         * @custom:contributor Matt Solomon (msolomon.eth)
         * @custom:contributor Weikang Song (weikangs.eth)
         * @custom:contributor zer0dot (zer0dot.eth)
         * @custom:contributor Mudit Gupta (mudit.eth)
         * @custom:contributor leonardoalt (leoalt.eth)
         * @custom:contributor cmichel (cmichel.eth)
         * @custom:contributor PraneshASP (pranesh.eth)
         * @custom:contributor JasperAlexander (jasperalexander.eth)
         * @custom:contributor Ellahi (ellahi.eth)
         * @custom:contributor zaz (1zaz1.eth)
         * @custom:contributor berndartmueller (berndartmueller.eth)
         * @custom:contributor dmfxyz (dmfxyz.eth)
         * @custom:contributor daltoncoder (dontkillrobots.eth)
         * @custom:contributor 0xf4ce (0xf4ce.eth)
         * @custom:contributor phaze (phaze.eth)
         * @custom:contributor hrkrshnn (hrkrshnn.eth)
         * @custom:contributor axic (axic.eth)
         * @custom:contributor leastwood (leastwood.eth)
         * @custom:contributor 0xsanson (sanson.eth)
         * @custom:contributor blockdev (blockd3v.eth)
         * @custom:contributor fiveoutofnine (fiveoutofnine.eth)
         * @custom:contributor shuklaayush (shuklaayush.eth)
         * @custom:contributor dravee (dravee.eth)
         * @custom:contributor 0xPatissier
         * @custom:contributor pcaversaccio
         * @custom:contributor David Eiber
         * @custom:contributor csanuragjain
         * @custom:contributor sach1r0
         * @custom:contributor twojoy0
         * @custom:contributor ori_dabush
         * @custom:contributor Daniel Gelfand
         * @custom:contributor okkothejawa
         * @custom:contributor FlameHorizon
         * @custom:contributor vdrg
         * @custom:contributor dmitriia
         * @custom:contributor bokeh-eth
         * @custom:contributor asutorufos
         * @custom:contributor rfart(rfa)
         * @custom:contributor Riley Holterhus
         * @custom:contributor big-tech-sux
         * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155
         *         marketplace with lightweight methods for common routes as well as
         *         more flexible methods for composing advanced orders or groups of
         *         orders. Each order contains an arbitrary number of items that may be
         *         spent (the "offer") along with an arbitrary number of items that must
         *         be received back by the indicated recipients (the "consideration").
         */
        contract Seaport is Consideration {
            /**
             * @notice Derive and set hashes, reference chainId, and associated domain
             *         separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) Consideration(conduitController) {}
            /**
             * @dev Internal pure function to retrieve and return the name of this
             *      contract.
             *
             * @return The name of this contract.
             */
            function _name() internal pure override returns (string memory) {
                // Return the name of the contract.
                assembly {
                    mstore(0x20, 0x20)
                    mstore(0x47, 0x07536561706f7274)
                    return(0x20, 0x60)
                }
            }
            /**
             * @dev Internal pure function to retrieve the name of this contract as a
             *      string that will be used to derive the name hash in the constructor.
             *
             * @return The name of this contract as a string.
             */
            function _nameString() internal pure override returns (string memory) {
                // Return the name of the contract.
                return "Seaport";
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ConsiderationInterface
        } from "seaport-types/src/interfaces/ConsiderationInterface.sol";
        import {
            AdvancedOrder,
            BasicOrderParameters,
            CriteriaResolver,
            Execution,
            Fulfillment,
            FulfillmentComponent,
            Order,
            OrderComponents
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { OrderCombiner } from "./OrderCombiner.sol";
        import {
            CalldataStart,
            CalldataPointer
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        import {
            Offset_fulfillAdvancedOrder_criteriaResolvers,
            Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts,
            Offset_fulfillAvailableAdvancedOrders_criteriaResolvers,
            Offset_fulfillAvailableAdvancedOrders_offerFulfillments,
            Offset_fulfillAvailableOrders_considerationFulfillments,
            Offset_fulfillAvailableOrders_offerFulfillments,
            Offset_matchAdvancedOrders_criteriaResolvers,
            Offset_matchAdvancedOrders_fulfillments,
            Offset_matchOrders_fulfillments,
            OrderParameters_counter_offset
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        /**
         * @title Consideration
         * @author 0age (0age.eth)
         * @custom:coauthor d1ll0n (d1ll0n.eth)
         * @custom:coauthor transmissions11 (t11s.eth)
         * @custom:coauthor James Wenzel (emo.eth)
         * @custom:coauthor Daniel Viau (snotrocket.eth)
         * @custom:version 1.6
         * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155
         *         marketplace that provides lightweight methods for common routes as
         *         well as more flexible methods for composing advanced orders or groups
         *         of orders. Each order contains an arbitrary number of items that may
         *         be spent (the "offer") along with an arbitrary number of items that
         *         must be received back by the indicated recipients (the
         *         "consideration").
         */
        contract Consideration is ConsiderationInterface, OrderCombiner {
            /**
             * @notice Derive and set hashes, reference chainId, and associated domain
             *         separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) OrderCombiner(conduitController) {}
            /**
             * @notice Accept native token transfers during execution that may then be
             *         used to facilitate native token transfers, where any tokens that
             *         remain will be transferred to the caller. Native tokens are only
             *         acceptable mid-fulfillment (and not during basic fulfillment).
             */
            receive() external payable {
                // Ensure the reentrancy guard is currently set to accept native tokens.
                _assertAcceptingNativeTokens();
            }
            /**
             * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by
             *         supplying Ether (or other native tokens), ERC20 tokens, an ERC721
             *         item, or an ERC1155 item as consideration. Six permutations are
             *         supported: Native token to ERC721, Native token to ERC1155, ERC20
             *         to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to
             *         ERC20 (with native tokens supplied as msg.value). For an order to
             *         be eligible for fulfillment via this method, it must contain a
             *         single offer item (though that item may have a greater amount if
             *         the item is not an ERC721). An arbitrary number of "additional
             *         recipients" may also be supplied which will each receive native
             *         tokens or ERC20 items from the fulfiller as consideration. Refer
             *         to the documentation for a more comprehensive summary of how to
             *         utilize this method and what orders are compatible with it.
             *
             * @custom:param parameters Additional information on the fulfilled order.
             *                          Note that the offerer and the fulfiller must
             *                          first approve this contract (or their chosen
             *                          conduit if indicated) before any tokens can be
             *                          transferred. Also note that contract recipients
             *                          of ERC1155 consideration items must implement
             *                          `onERC1155Received` to receive those items.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillBasicOrder(
                /**
                 * @custom:name parameters
                 */
                BasicOrderParameters calldata
            ) external payable override returns (bool fulfilled) {
                // Validate and fulfill the basic order.
                fulfilled = _validateAndFulfillBasicOrder();
            }
            /**
             * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by
             *         supplying Ether (or other native tokens), ERC20 tokens, an ERC721
             *         item, or an ERC1155 item as consideration. Six permutations are
             *         supported: Native token to ERC721, Native token to ERC1155, ERC20
             *         to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to
             *         ERC20 (with native tokens supplied as msg.value). For an order to
             *         be eligible for fulfillment via this method, it must contain a
             *         single offer item (though that item may have a greater amount if
             *         the item is not an ERC721). An arbitrary number of "additional
             *         recipients" may also be supplied which will each receive native
             *         tokens or ERC20 items from the fulfiller as consideration. Refer
             *         to the documentation for a more comprehensive summary of how to
             *         utilize this method and what orders are compatible with it. Note
             *         that this function costs less gas than `fulfillBasicOrder` due to
             *         the zero bytes in the function selector (0x00000000) which also
             *         results in earlier function dispatch.
             *
             * @custom:param parameters Additional information on the fulfilled order.
             *                          Note that the offerer and the fulfiller must
             *                          first approve this contract (or their chosen
             *                          conduit if indicated) before any tokens can be
             *                          transferred. Also note that contract recipients
             *                          of ERC1155 consideration items must implement
             *                          `onERC1155Received` to receive those items.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillBasicOrder_efficient_6GL6yc(
                /**
                 * @custom:name parameters
                 */
                BasicOrderParameters calldata
            ) external payable override returns (bool fulfilled) {
                // Validate and fulfill the basic order.
                fulfilled = _validateAndFulfillBasicOrder();
            }
            /**
             * @notice Fulfill an order with an arbitrary number of items for offer and
             *         consideration. Note that this function does not support
             *         criteria-based orders or partial filling of orders (though
             *         filling the remainder of a partially-filled order is supported).
             *
             * @custom:param order        The order to fulfill. Note that both the
             *                            offerer and the fulfiller must first approve
             *                            this contract (or the corresponding conduit if
             *                            indicated) to transfer any relevant tokens on
             *                            their behalf and that contracts must implement
             *                            `onERC1155Received` to receive ERC1155 tokens
             *                            as consideration.
             * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
             *                            any, to source the fulfiller's token approvals
             *                            from. The zero hash signifies that no conduit
             *                            should be used (and direct approvals set on
             *                            this contract).
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillOrder(
                /**
                 * @custom:name order
                 */
                Order calldata,
                bytes32 fulfillerConduitKey
            ) external payable override returns (bool fulfilled) {
                // Convert order to "advanced" order, then validate and fulfill it.
                fulfilled = _validateAndFulfillAdvancedOrder(
                    _toAdvancedOrderReturnType(_decodeOrderAsAdvancedOrder)(
                        CalldataStart.pptr()
                    ),
                    new CriteriaResolver[](0), // No criteria resolvers supplied.
                    fulfillerConduitKey,
                    msg.sender
                );
            }
            /**
             * @notice Fill an order, fully or partially, with an arbitrary number of
             *         items for offer and consideration alongside criteria resolvers
             *         containing specific token identifiers and associated proofs.
             *
             * @custom:param advancedOrder     The order to fulfill along with the
             *                                 fraction of the order to attempt to fill.
             *                                 Note that both the offerer and the
             *                                 fulfiller must first approve this
             *                                 contract (or their conduit if indicated
             *                                 by the order) to transfer any relevant
             *                                 tokens on their behalf and that contracts
             *                                 must implement `onERC1155Received` to
             *                                 receive ERC1155 tokens as consideration.
             *                                 Also note that all offer and
             *                                 consideration components must have no
             *                                 remainder after multiplication of the
             *                                 respective amount with the supplied
             *                                 fraction for the partial fill to be
             *                                 considered valid.
             * @custom:param criteriaResolvers An array where each element contains a
             *                                 reference to a specific offer or
             *                                 consideration, a token identifier, and a
             *                                 proof that the supplied token identifier
             *                                 is contained in the merkle root held by
             *                                 the item in question's criteria element.
             *                                 Note that an empty criteria indicates
             *                                 that any (transferable) token identifier
             *                                 on the token in question is valid and
             *                                 that no associated proof needs to be
             *                                 supplied.
             * @param fulfillerConduitKey      A bytes32 value indicating what conduit,
             *                                 if any, to source the fulfiller's token
             *                                 approvals from. The zero hash signifies
             *                                 that no conduit should be used (and
             *                                 direct approvals set on this contract).
             * @param recipient                The intended recipient for all received
             *                                 items, with `address(0)` indicating that
             *                                 the caller should receive the items.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillAdvancedOrder(
                /**
                 * @custom:name advancedOrder
                 */
                AdvancedOrder calldata,
                /**
                 * @custom:name criteriaResolvers
                 */
                CriteriaResolver[] calldata,
                bytes32 fulfillerConduitKey,
                address recipient
            ) external payable override returns (bool fulfilled) {
                // Validate and fulfill the order.
                fulfilled = _validateAndFulfillAdvancedOrder(
                    _toAdvancedOrderReturnType(_decodeAdvancedOrder)(
                        CalldataStart.pptr()
                    ),
                    _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                        CalldataStart.pptrOffset(
                            Offset_fulfillAdvancedOrder_criteriaResolvers
                        )
                    ),
                    fulfillerConduitKey,
                    _substituteCallerForEmptyRecipient(recipient)
                );
            }
            /**
             * @notice Attempt to fill a group of orders, each with an arbitrary number
             *         of items for offer and consideration. Any order that is not
             *         currently active, has already been fully filled, or has been
             *         cancelled will be omitted. Remaining offer and consideration
             *         items will then be aggregated where possible as indicated by the
             *         supplied offer and consideration component arrays and aggregated
             *         items will be transferred to the fulfiller or to each intended
             *         recipient, respectively. Note that a failing item transfer or an
             *         issue with order formatting will cause the entire batch to fail.
             *         Note that this function does not support criteria-based orders or
             *         partial filling of orders (though filling the remainder of a
             *         partially-filled order is supported).
             *
             * @custom:param orders                    The orders to fulfill. Note that
             *                                         both the offerer and the
             *                                         fulfiller must first approve this
             *                                         contract (or the corresponding
             *                                         conduit if indicated) to transfer
             *                                         any relevant tokens on their
             *                                         behalf and that contracts must
             *                                         implement `onERC1155Received` to
             *                                         receive ERC1155 tokens as
             *                                         consideration.
             * @custom:param offerFulfillments         An array of FulfillmentComponent
             *                                         arrays indicating which offer
             *                                         items to attempt to aggregate
             *                                         when preparing executions. Note
             *                                         that any offer items not included
             *                                         as part of a fulfillment will be
             *                                         sent unaggregated to the caller.
             * @custom:param considerationFulfillments An array of FulfillmentComponent
             *                                         arrays indicating which
             *                                         consideration items to attempt to
             *                                         aggregate when preparing
             *                                         executions.
             * @param fulfillerConduitKey              A bytes32 value indicating what
             *                                         conduit, if any, to source the
             *                                         fulfiller's token approvals from.
             *                                         The zero hash signifies that no
             *                                         conduit should be used (and
             *                                         direct approvals set on this
             *                                         contract).
             * @param maximumFulfilled                 The maximum number of orders to
             *                                         fulfill.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders.
             */
            function fulfillAvailableOrders(
                /**
                 * @custom:name orders
                 */
                Order[] calldata,
                /**
                 * @custom:name offerFulfillments
                 */
                FulfillmentComponent[][] calldata,
                /**
                 * @custom:name considerationFulfillments
                 */
                FulfillmentComponent[][] calldata,
                bytes32 fulfillerConduitKey,
                uint256 maximumFulfilled
            )
                external
                payable
                override
                returns (
                    bool[] memory /* availableOrders */,
                    Execution[] memory /* executions */
                )
            {
                // Convert orders to "advanced" orders and fulfill all available orders.
                return
                    _fulfillAvailableAdvancedOrders(
                        _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)(
                            CalldataStart.pptr()
                        ), // Convert to advanced orders.
                        new CriteriaResolver[](0), // No criteria resolvers supplied.
                        _toNestedFulfillmentComponentsReturnType(
                            _decodeNestedFulfillmentComponents
                        )(
                            CalldataStart.pptrOffset(
                                Offset_fulfillAvailableOrders_offerFulfillments
                            )
                        ),
                        _toNestedFulfillmentComponentsReturnType(
                            _decodeNestedFulfillmentComponents
                        )(
                            CalldataStart.pptrOffset(
                                Offset_fulfillAvailableOrders_considerationFulfillments
                            )
                        ),
                        fulfillerConduitKey,
                        msg.sender,
                        maximumFulfilled
                    );
            }
            /**
             * @notice Attempt to fill a group of orders, fully or partially, with an
             *         arbitrary number of items for offer and consideration per order
             *         alongside criteria resolvers containing specific token
             *         identifiers and associated proofs. Any order that is not
             *         currently active, has already been fully filled, or has been
             *         cancelled will be omitted. Remaining offer and consideration
             *         items will then be aggregated where possible as indicated by the
             *         supplied offer and consideration component arrays and aggregated
             *         items will be transferred to the fulfiller or to each intended
             *         recipient, respectively. Note that a failing item transfer or an
             *         issue with order formatting will cause the entire batch to fail.
             *
             * @custom:param advancedOrders            The orders to fulfill along with
             *                                         the fraction of those orders to
             *                                         attempt to fill. Note that both
             *                                         the offerer and the fulfiller
             *                                         must first approve this contract
             *                                         (or their conduit if indicated by
             *                                         the order) to transfer any
             *                                         relevant tokens on their behalf
             *                                         and that contracts must implement
             *                                         `onERC1155Received` to receive
             *                                         ERC1155 tokens as consideration.
             *                                         Also note that all offer and
             *                                         consideration components must
             *                                         have no remainder after
             *                                         multiplication of the respective
             *                                         amount with the supplied fraction
             *                                         for an order's partial fill
             *                                         amount to be considered valid.
             * @custom:param criteriaResolvers         An array where each element
             *                                         contains a reference to a
             *                                         specific offer or consideration,
             *                                         a token identifier, and a proof
             *                                         that the supplied token
             *                                         identifier is contained in the
             *                                         merkle root held by the item in
             *                                         question's criteria element. Note
             *                                         that an empty criteria indicates
             *                                         that any (transferable) token
             *                                         identifier on the token in
             *                                         question is valid and that no
             *                                         associated proof needs to be
             *                                         supplied.
             * @custom:param offerFulfillments         An array of FulfillmentComponent
             *                                         arrays indicating which offer
             *                                         items to attempt to aggregate
             *                                         when preparing executions. Note
             *                                         that any offer items not included
             *                                         as part of a fulfillment will be
             *                                         sent unaggregated to the caller.
             * @custom:param considerationFulfillments An array of FulfillmentComponent
             *                                         arrays indicating which
             *                                         consideration items to attempt to
             *                                         aggregate when preparing
             *                                         executions.
             * @param fulfillerConduitKey              A bytes32 value indicating what
             *                                         conduit, if any, to source the
             *                                         fulfiller's token approvals from.
             *                                         The zero hash signifies that no
             *                                         conduit should be used (and
             *                                         direct approvals set on this
             *                                         contract).
             * @param recipient                        The intended recipient for all
             *                                         received items, with `address(0)`
             *                                         indicating that the caller should
             *                                         receive the offer items.
             * @param maximumFulfilled                 The maximum number of orders to
             *                                         fulfill.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders.
             */
            function fulfillAvailableAdvancedOrders(
                /**
                 * @custom:name advancedOrders
                 */
                AdvancedOrder[] calldata,
                /**
                 * @custom:name criteriaResolvers
                 */
                CriteriaResolver[] calldata,
                /**
                 * @custom:name offerFulfillments
                 */
                FulfillmentComponent[][] calldata,
                /**
                 * @custom:name considerationFulfillments
                 */
                FulfillmentComponent[][] calldata,
                bytes32 fulfillerConduitKey,
                address recipient,
                uint256 maximumFulfilled
            )
                external
                payable
                override
                returns (
                    bool[] memory /* availableOrders */,
                    Execution[] memory /* executions */
                )
            {
                // Fulfill all available orders.
                return
                    _fulfillAvailableAdvancedOrders(
                        _toAdvancedOrdersReturnType(_decodeAdvancedOrders)(
                            CalldataStart.pptr()
                        ),
                        _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                            CalldataStart.pptrOffset(
                                Offset_fulfillAvailableAdvancedOrders_criteriaResolvers
                            )
                        ),
                        _toNestedFulfillmentComponentsReturnType(
                            _decodeNestedFulfillmentComponents
                        )(
                            CalldataStart.pptrOffset(
                                Offset_fulfillAvailableAdvancedOrders_offerFulfillments
                            )
                        ),
                        _toNestedFulfillmentComponentsReturnType(
                            _decodeNestedFulfillmentComponents
                        )(
                            CalldataStart.pptrOffset(
                                Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts
                            )
                        ),
                        fulfillerConduitKey,
                        _substituteCallerForEmptyRecipient(recipient),
                        maximumFulfilled
                    );
            }
            /**
             * @notice Match an arbitrary number of orders, each with an arbitrary
             *         number of items for offer and consideration along with a set of
             *         fulfillments allocating offer components to consideration
             *         components. Note that this function does not support
             *         criteria-based or partial filling of orders (though filling the
             *         remainder of a partially-filled order is supported). Any unspent
             *         offer item amounts or native tokens will be transferred to the
             *         caller.
             *
             * @custom:param orders       The orders to match. Note that both the
             *                            offerer and fulfiller on each order must first
             *                            approve this contract (or their conduit if
             *                            indicated by the order) to transfer any
             *                            relevant tokens on their behalf and each
             *                            consideration recipient must implement
             *                            `onERC1155Received` to receive ERC1155 tokens.
             * @custom:param fulfillments An array of elements allocating offer
             *                            components to consideration components. Note
             *                            that each consideration component must be
             *                            fully met for the match operation to be valid,
             *                            and that any unspent offer items will be sent
             *                            unaggregated to the caller.
             *
             * @return executions An array of elements indicating the sequence of
             *                    transfers performed as part of matching the given
             *                    orders. Note that unspent offer item amounts or native
             *                    tokens will not be reflected as part of this array.
             */
            function matchOrders(
                /**
                 * @custom:name orders
                 */
                Order[] calldata,
                /**
                 * @custom:name fulfillments
                 */
                Fulfillment[] calldata
            ) external payable override returns (Execution[] memory /* executions */) {
                // Convert to advanced, validate, and match orders using fulfillments.
                return
                    _matchAdvancedOrders(
                        _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)(
                            CalldataStart.pptr()
                        ),
                        new CriteriaResolver[](0), // No criteria resolvers supplied.
                        _toFulfillmentsReturnType(_decodeFulfillments)(
                            CalldataStart.pptrOffset(Offset_matchOrders_fulfillments)
                        ),
                        msg.sender
                    );
            }
            /**
             * @notice Match an arbitrary number of full, partial, or contract orders,
             *         each with an arbitrary number of items for offer and
             *         consideration, supplying criteria resolvers containing specific
             *         token identifiers and associated proofs as well as fulfillments
             *         allocating offer components to consideration components. Any
             *         unspent offer item amounts will be transferred to the designated
             *         recipient (with the null address signifying to use the caller)
             *         and any unspent native tokens will be returned to the caller.
             *
             * @custom:param advancedOrders    The advanced orders to match. Note that
             *                                 both the offerer and fulfiller on each
             *                                 order must first approve this contract
             *                                 (or their conduit if indicated by the
             *                                 order) to transfer any relevant tokens on
             *                                 their behalf and each consideration
             *                                 recipient must implement
             *                                 `onERC1155Received` to receive ERC1155
             *                                 tokens. Also note that the offer and
             *                                 consideration components for each order
             *                                 must have no remainder after multiplying
             *                                 the respective amount with the supplied
             *                                 fraction for the group of partial fills
             *                                 to be considered valid.
             * @custom:param criteriaResolvers An array where each element contains a
             *                                 reference to a specific offer or
             *                                 consideration, a token identifier, and a
             *                                 proof that the supplied token identifier
             *                                 is contained in the merkle root held by
             *                                 the item in question's criteria element.
             *                                 Note that an empty criteria indicates
             *                                 that any (transferable) token identifier
             *                                 on the token in question is valid and
             *                                 that no associated proof needs to be
             *                                 supplied.
             * @custom:param fulfillments      An array of elements allocating offer
             *                                 components to consideration components.
             *                                 Note that each consideration component
             *                                 must be fully met for the match operation
             *                                 to be valid, and that any unspent offer
             *                                 items will be sent unaggregated to the
             *                                 designated recipient.
             * @param recipient                The intended recipient for all unspent
             *                                 offer item amounts, or the caller if the
             *                                 null address is supplied.
             *
             * @return executions An array of elements indicating the sequence of
             *                     transfers performed as part of matching the given
             *                     orders. Note that unspent offer item amounts or
             *                     native tokens will not be reflected as part of this
             *                     array.
             */
            function matchAdvancedOrders(
                /**
                 * @custom:name advancedOrders
                 */
                AdvancedOrder[] calldata,
                /**
                 * @custom:name criteriaResolvers
                 */
                CriteriaResolver[] calldata,
                /**
                 * @custom:name fulfillments
                 */
                Fulfillment[] calldata,
                address recipient
            ) external payable override returns (Execution[] memory /* executions */) {
                // Validate and match the advanced orders using supplied fulfillments.
                return
                    _matchAdvancedOrders(
                        _toAdvancedOrdersReturnType(_decodeAdvancedOrders)(
                            CalldataStart.pptr()
                        ),
                        _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                            CalldataStart.pptrOffset(
                                Offset_matchAdvancedOrders_criteriaResolvers
                            )
                        ),
                        _toFulfillmentsReturnType(_decodeFulfillments)(
                            CalldataStart.pptrOffset(
                                Offset_matchAdvancedOrders_fulfillments
                            )
                        ),
                        _substituteCallerForEmptyRecipient(recipient)
                    );
            }
            /**
             * @notice Cancel an arbitrary number of orders. Note that only the offerer
             *         or the zone of a given order may cancel it. Callers should ensure
             *         that the intended order was cancelled by calling `getOrderStatus`
             *         and confirming that `isCancelled` returns `true`.
             *
             * @param orders The orders to cancel.
             *
             * @return cancelled A boolean indicating whether the supplied orders have
             *                   been successfully cancelled.
             */
            function cancel(
                OrderComponents[] calldata orders
            ) external override returns (bool cancelled) {
                // Cancel the orders.
                cancelled = _cancel(orders);
            }
            /**
             * @notice Validate an arbitrary number of orders, thereby registering their
             *         signatures as valid and allowing the fulfiller to skip signature
             *         verification on fulfillment. Note that validated orders may still
             *         be unfulfillable due to invalid item amounts or other factors;
             *         callers should determine whether validated orders are fulfillable
             *         by simulating the fulfillment call prior to execution. Also note
             *         that anyone can validate a signed order, but only the offerer can
             *         validate an order without supplying a signature.
             *
             * @custom:param orders The orders to validate.
             *
             * @return validated A boolean indicating whether the supplied orders have
             *                   been successfully validated.
             */
            function validate(
                /**
                 * @custom:name orders
                 */
                Order[] calldata
            ) external override returns (bool /* validated */) {
                return
                    _validate(_toOrdersReturnType(_decodeOrders)(CalldataStart.pptr()));
            }
            /**
             * @notice Cancel all orders from a given offerer with a given zone in bulk
             *         by incrementing a counter. Note that only the offerer may
             *         increment the counter.
             *
             * @return newCounter The new counter.
             */
            function incrementCounter() external override returns (uint256 newCounter) {
                // Increment current counter for the supplied offerer.  Note that the
                // counter is incremented by a large, quasi-random interval.
                newCounter = _incrementCounter();
            }
            /**
             * @notice Retrieve the order hash for a given order.
             *
             * @custom:param order The components of the order.
             *
             * @return orderHash The order hash.
             */
            function getOrderHash(
                /**
                 * @custom:name order
                 */
                OrderComponents calldata
            ) external view override returns (bytes32 orderHash) {
                CalldataPointer orderPointer = CalldataStart.pptr();
                // Derive order hash by supplying order parameters along with counter.
                orderHash = _deriveOrderHash(
                    _toOrderParametersReturnType(
                        _decodeOrderComponentsAsOrderParameters
                    )(orderPointer),
                    // Read order counter
                    orderPointer.offset(OrderParameters_counter_offset).readUint256()
                );
            }
            /**
             * @notice Retrieve the status of a given order by hash, including whether
             *         the order has been cancelled or validated and the fraction of the
             *         order that has been filled. Since the _orderStatus[orderHash]
             *         does not get set for contract orders, getOrderStatus will always
             *         return (false, false, 0, 0) for those hashes. Note that this
             *         function is susceptible to view reentrancy and so should be used
             *         with care when calling from other contracts.
             *
             * @param orderHash The order hash in question.
             *
             * @return isValidated A boolean indicating whether the order in question
             *                     has been validated (i.e. previously approved or
             *                     partially filled).
             * @return isCancelled A boolean indicating whether the order in question
             *                     has been cancelled.
             * @return totalFilled The total portion of the order that has been filled
             *                     (i.e. the "numerator").
             * @return totalSize   The total size of the order that is either filled or
             *                     unfilled (i.e. the "denominator").
             */
            function getOrderStatus(
                bytes32 orderHash
            )
                external
                view
                override
                returns (
                    bool isValidated,
                    bool isCancelled,
                    uint256 totalFilled,
                    uint256 totalSize
                )
            {
                // Retrieve the order status using the order hash.
                return _getOrderStatus(orderHash);
            }
            /**
             * @notice Retrieve the current counter for a given offerer.
             *
             * @param offerer The offerer in question.
             *
             * @return counter The current counter.
             */
            function getCounter(
                address offerer
            ) external view override returns (uint256 counter) {
                // Return the counter for the supplied offerer.
                counter = _getCounter(offerer);
            }
            /**
             * @notice Retrieve configuration information for this contract.
             *
             * @return version           The contract version.
             * @return domainSeparator   The domain separator for this contract.
             * @return conduitController The conduit Controller set for this contract.
             */
            function information()
                external
                view
                override
                returns (
                    string memory version,
                    bytes32 domainSeparator,
                    address conduitController
                )
            {
                // Return the information for this contract.
                return _information();
            }
            /**
             * @dev Gets the contract offerer nonce for the specified contract offerer.
             *      Note that this function is susceptible to view reentrancy and so
             *      should be used with care when calling from other contracts.
             *
             * @param contractOfferer The contract offerer for which to get the nonce.
             *
             * @return nonce The contract offerer nonce.
             */
            function getContractOffererNonce(
                address contractOfferer
            ) external view override returns (uint256 nonce) {
                nonce = _contractNonces[contractOfferer];
            }
            /**
             * @notice Retrieve the name of this contract.
             *
             * @return contractName The name of this contract.
             */
            function name()
                external
                pure
                override
                returns (string memory /* contractName */)
            {
                // Return the name of the contract.
                return _name();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import {
            AdvancedOrder,
            BasicOrderParameters,
            CriteriaResolver,
            Execution,
            Fulfillment,
            FulfillmentComponent,
            Order,
            OrderComponents
        } from "../lib/ConsiderationStructs.sol";
        /**
         * @title ConsiderationInterface
         * @author 0age
         * @custom:version 1.6
         * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155
         *         marketplace. It minimizes external calls to the greatest extent
         *         possible and provides lightweight methods for common routes as well
         *         as more flexible methods for composing advanced orders.
         *
         * @dev ConsiderationInterface contains all external function interfaces for
         *      Consideration.
         */
        interface ConsiderationInterface {
            /**
             * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
             *         the native token for the given chain) as consideration for the
             *         order. An arbitrary number of "additional recipients" may also be
             *         supplied which will each receive native tokens from the fulfiller
             *         as consideration.
             *
             * @param parameters Additional information on the fulfilled order. Note
             *                   that the offerer must first approve this contract (or
             *                   their preferred conduit if indicated by the order) for
             *                   their offered ERC721 token to be transferred.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillBasicOrder(
                BasicOrderParameters calldata parameters
            ) external payable returns (bool fulfilled);
            /**
             * @notice Fulfill an order with an arbitrary number of items for offer and
             *         consideration. Note that this function does not support
             *         criteria-based orders or partial filling of orders (though
             *         filling the remainder of a partially-filled order is supported).
             *
             * @param order               The order to fulfill. Note that both the
             *                            offerer and the fulfiller must first approve
             *                            this contract (or the corresponding conduit if
             *                            indicated) to transfer any relevant tokens on
             *                            their behalf and that contracts must implement
             *                            `onERC1155Received` to receive ERC1155 tokens
             *                            as consideration.
             * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
             *                            any, to source the fulfiller's token approvals
             *                            from. The zero hash signifies that no conduit
             *                            should be used, with direct approvals set on
             *                            Consideration.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillOrder(
                Order calldata order,
                bytes32 fulfillerConduitKey
            ) external payable returns (bool fulfilled);
            /**
             * @notice Fill an order, fully or partially, with an arbitrary number of
             *         items for offer and consideration alongside criteria resolvers
             *         containing specific token identifiers and associated proofs.
             *
             * @param advancedOrder       The order to fulfill along with the fraction
             *                            of the order to attempt to fill. Note that
             *                            both the offerer and the fulfiller must first
             *                            approve this contract (or their preferred
             *                            conduit if indicated by the order) to transfer
             *                            any relevant tokens on their behalf and that
             *                            contracts must implement `onERC1155Received`
             *                            to receive ERC1155 tokens as consideration.
             *                            Also note that all offer and consideration
             *                            components must have no remainder after
             *                            multiplication of the respective amount with
             *                            the supplied fraction for the partial fill to
             *                            be considered valid.
             * @param criteriaResolvers   An array where each element contains a
             *                            reference to a specific offer or
             *                            consideration, a token identifier, and a proof
             *                            that the supplied token identifier is
             *                            contained in the merkle root held by the item
             *                            in question's criteria element. Note that an
             *                            empty criteria indicates that any
             *                            (transferable) token identifier on the token
             *                            in question is valid and that no associated
             *                            proof needs to be supplied.
             * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
             *                            any, to source the fulfiller's token approvals
             *                            from. The zero hash signifies that no conduit
             *                            should be used, with direct approvals set on
             *                            Consideration.
             * @param recipient           The intended recipient for all received items,
             *                            with `address(0)` indicating that the caller
             *                            should receive the items.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillAdvancedOrder(
                AdvancedOrder calldata advancedOrder,
                CriteriaResolver[] calldata criteriaResolvers,
                bytes32 fulfillerConduitKey,
                address recipient
            ) external payable returns (bool fulfilled);
            /**
             * @notice Attempt to fill a group of orders, each with an arbitrary number
             *         of items for offer and consideration. Any order that is not
             *         currently active, has already been fully filled, or has been
             *         cancelled will be omitted. Remaining offer and consideration
             *         items will then be aggregated where possible as indicated by the
             *         supplied offer and consideration component arrays and aggregated
             *         items will be transferred to the fulfiller or to each intended
             *         recipient, respectively. Note that a failing item transfer or an
             *         issue with order formatting will cause the entire batch to fail.
             *         Note that this function does not support criteria-based orders or
             *         partial filling of orders (though filling the remainder of a
             *         partially-filled order is supported).
             *
             * @param orders                    The orders to fulfill. Note that both
             *                                  the offerer and the fulfiller must first
             *                                  approve this contract (or the
             *                                  corresponding conduit if indicated) to
             *                                  transfer any relevant tokens on their
             *                                  behalf and that contracts must implement
             *                                  `onERC1155Received` to receive ERC1155
             *                                  tokens as consideration.
             * @param offerFulfillments         An array of FulfillmentComponent arrays
             *                                  indicating which offer items to attempt
             *                                  to aggregate when preparing executions.
             * @param considerationFulfillments An array of FulfillmentComponent arrays
             *                                  indicating which consideration items to
             *                                  attempt to aggregate when preparing
             *                                  executions.
             * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
             *                                  if any, to source the fulfiller's token
             *                                  approvals from. The zero hash signifies
             *                                  that no conduit should be used, with
             *                                  direct approvals set on this contract.
             * @param maximumFulfilled          The maximum number of orders to fulfill.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders. Note that unspent offer item amounts or
             *                         native tokens will not be reflected as part of
             *                         this array.
             */
            function fulfillAvailableOrders(
                Order[] calldata orders,
                FulfillmentComponent[][] calldata offerFulfillments,
                FulfillmentComponent[][] calldata considerationFulfillments,
                bytes32 fulfillerConduitKey,
                uint256 maximumFulfilled
            )
                external
                payable
                returns (bool[] memory availableOrders, Execution[] memory executions);
            /**
             * @notice Attempt to fill a group of orders, fully or partially, with an
             *         arbitrary number of items for offer and consideration per order
             *         alongside criteria resolvers containing specific token
             *         identifiers and associated proofs. Any order that is not
             *         currently active, has already been fully filled, or has been
             *         cancelled will be omitted. Remaining offer and consideration
             *         items will then be aggregated where possible as indicated by the
             *         supplied offer and consideration component arrays and aggregated
             *         items will be transferred to the fulfiller or to each intended
             *         recipient, respectively. Note that a failing item transfer or an
             *         issue with order formatting will cause the entire batch to fail.
             *
             * @param advancedOrders            The orders to fulfill along with the
             *                                  fraction of those orders to attempt to
             *                                  fill. Note that both the offerer and the
             *                                  fulfiller must first approve this
             *                                  contract (or their preferred conduit if
             *                                  indicated by the order) to transfer any
             *                                  relevant tokens on their behalf and that
             *                                  contracts must implement
             *                                  `onERC1155Received` to enable receipt of
             *                                  ERC1155 tokens as consideration. Also
             *                                  note that all offer and consideration
             *                                  components must have no remainder after
             *                                  multiplication of the respective amount
             *                                  with the supplied fraction for an
             *                                  order's partial fill amount to be
             *                                  considered valid.
             * @param criteriaResolvers         An array where each element contains a
             *                                  reference to a specific offer or
             *                                  consideration, a token identifier, and a
             *                                  proof that the supplied token identifier
             *                                  is contained in the merkle root held by
             *                                  the item in question's criteria element.
             *                                  Note that an empty criteria indicates
             *                                  that any (transferable) token
             *                                  identifier on the token in question is
             *                                  valid and that no associated proof needs
             *                                  to be supplied.
             * @param offerFulfillments         An array of FulfillmentComponent arrays
             *                                  indicating which offer items to attempt
             *                                  to aggregate when preparing executions.
             * @param considerationFulfillments An array of FulfillmentComponent arrays
             *                                  indicating which consideration items to
             *                                  attempt to aggregate when preparing
             *                                  executions.
             * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
             *                                  if any, to source the fulfiller's token
             *                                  approvals from. The zero hash signifies
             *                                  that no conduit should be used, with
             *                                  direct approvals set on this contract.
             * @param recipient                 The intended recipient for all received
             *                                  items, with `address(0)` indicating that
             *                                  the caller should receive the items.
             * @param maximumFulfilled          The maximum number of orders to fulfill.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders. Note that unspent offer item amounts or
             *                         native tokens will not be reflected as part of
             *                         this array.
             */
            function fulfillAvailableAdvancedOrders(
                AdvancedOrder[] calldata advancedOrders,
                CriteriaResolver[] calldata criteriaResolvers,
                FulfillmentComponent[][] calldata offerFulfillments,
                FulfillmentComponent[][] calldata considerationFulfillments,
                bytes32 fulfillerConduitKey,
                address recipient,
                uint256 maximumFulfilled
            )
                external
                payable
                returns (bool[] memory availableOrders, Execution[] memory executions);
            /**
             * @notice Match an arbitrary number of orders, each with an arbitrary
             *         number of items for offer and consideration along with a set of
             *         fulfillments allocating offer components to consideration
             *         components. Note that this function does not support
             *         criteria-based or partial filling of orders (though filling the
             *         remainder of a partially-filled order is supported). Any unspent
             *         offer item amounts or native tokens will be transferred to the
             *         caller.
             *
             * @param orders       The orders to match. Note that both the offerer and
             *                     fulfiller on each order must first approve this
             *                     contract (or their conduit if indicated by the order)
             *                     to transfer any relevant tokens on their behalf and
             *                     each consideration recipient must implement
             *                     `onERC1155Received` to enable ERC1155 token receipt.
             * @param fulfillments An array of elements allocating offer components to
             *                     consideration components. Note that each
             *                     consideration component must be fully met for the
             *                     match operation to be valid.
             *
             * @return executions An array of elements indicating the sequence of
             *                    transfers performed as part of matching the given
             *                    orders. Note that unspent offer item amounts or
             *                    native tokens will not be reflected as part of this
             *                    array.
             */
            function matchOrders(
                Order[] calldata orders,
                Fulfillment[] calldata fulfillments
            ) external payable returns (Execution[] memory executions);
            /**
             * @notice Match an arbitrary number of full or partial orders, each with an
             *         arbitrary number of items for offer and consideration, supplying
             *         criteria resolvers containing specific token identifiers and
             *         associated proofs as well as fulfillments allocating offer
             *         components to consideration components. Any unspent offer item
             *         amounts will be transferred to the designated recipient (with the
             *         null address signifying to use the caller) and any unspent native
             *         tokens will be returned to the caller.
             *
             * @param orders            The advanced orders to match. Note that both the
             *                          offerer and fulfiller on each order must first
             *                          approve this contract (or a preferred conduit if
             *                          indicated by the order) to transfer any relevant
             *                          tokens on their behalf and each consideration
             *                          recipient must implement `onERC1155Received` in
             *                          order to receive ERC1155 tokens. Also note that
             *                          the offer and consideration components for each
             *                          order must have no remainder after multiplying
             *                          the respective amount with the supplied fraction
             *                          in order for the group of partial fills to be
             *                          considered valid.
             * @param criteriaResolvers An array where each element contains a reference
             *                          to a specific order as well as that order's
             *                          offer or consideration, a token identifier, and
             *                          a proof that the supplied token identifier is
             *                          contained in the order's merkle root. Note that
             *                          an empty root indicates that any (transferable)
             *                          token identifier is valid and that no associated
             *                          proof needs to be supplied.
             * @param fulfillments      An array of elements allocating offer components
             *                          to consideration components. Note that each
             *                          consideration component must be fully met in
             *                          order for the match operation to be valid.
             * @param recipient         The intended recipient for all unspent offer
             *                          item amounts, or the caller if the null address
             *                          is supplied.
             *
             * @return executions An array of elements indicating the sequence of
             *                    transfers performed as part of matching the given
             *                    orders. Note that unspent offer item amounts or native
             *                    tokens will not be reflected as part of this array.
             */
            function matchAdvancedOrders(
                AdvancedOrder[] calldata orders,
                CriteriaResolver[] calldata criteriaResolvers,
                Fulfillment[] calldata fulfillments,
                address recipient
            ) external payable returns (Execution[] memory executions);
            /**
             * @notice Cancel an arbitrary number of orders. Note that only the offerer
             *         or the zone of a given order may cancel it. Callers should ensure
             *         that the intended order was cancelled by calling `getOrderStatus`
             *         and confirming that `isCancelled` returns `true`.
             *
             * @param orders The orders to cancel.
             *
             * @return cancelled A boolean indicating whether the supplied orders have
             *                   been successfully cancelled.
             */
            function cancel(
                OrderComponents[] calldata orders
            ) external returns (bool cancelled);
            /**
             * @notice Validate an arbitrary number of orders, thereby registering their
             *         signatures as valid and allowing the fulfiller to skip signature
             *         verification on fulfillment. Note that validated orders may still
             *         be unfulfillable due to invalid item amounts or other factors;
             *         callers should determine whether validated orders are fulfillable
             *         by simulating the fulfillment call prior to execution. Also note
             *         that anyone can validate a signed order, but only the offerer can
             *         validate an order without supplying a signature.
             *
             * @param orders The orders to validate.
             *
             * @return validated A boolean indicating whether the supplied orders have
             *                   been successfully validated.
             */
            function validate(
                Order[] calldata orders
            ) external returns (bool validated);
            /**
             * @notice Cancel all orders from a given offerer with a given zone in bulk
             *         by incrementing a counter. Note that only the offerer may
             *         increment the counter.
             *
             * @return newCounter The new counter.
             */
            function incrementCounter() external returns (uint256 newCounter);
            /**
             * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
             *         the native token for the given chain) as consideration for the
             *         order. An arbitrary number of "additional recipients" may also be
             *         supplied which will each receive native tokens from the fulfiller
             *         as consideration. Note that this function costs less gas than
             *         `fulfillBasicOrder` due to the zero bytes in the function
             *         selector (0x00000000) which also results in earlier function
             *         dispatch.
             *
             * @param parameters Additional information on the fulfilled order. Note
             *                   that the offerer must first approve this contract (or
             *                   their preferred conduit if indicated by the order) for
             *                   their offered ERC721 token to be transferred.
             *
             * @return fulfilled A boolean indicating whether the order has been
             *                   successfully fulfilled.
             */
            function fulfillBasicOrder_efficient_6GL6yc(
                BasicOrderParameters calldata parameters
            ) external payable returns (bool fulfilled);
            /**
             * @notice Retrieve the order hash for a given order.
             *
             * @param order The components of the order.
             *
             * @return orderHash The order hash.
             */
            function getOrderHash(
                OrderComponents calldata order
            ) external view returns (bytes32 orderHash);
            /**
             * @notice Retrieve the status of a given order by hash, including whether
             *         the order has been cancelled or validated and the fraction of the
             *         order that has been filled.
             *
             * @param orderHash The order hash in question.
             *
             * @return isValidated A boolean indicating whether the order in question
             *                     has been validated (i.e. previously approved or
             *                     partially filled).
             * @return isCancelled A boolean indicating whether the order in question
             *                     has been cancelled.
             * @return totalFilled The total portion of the order that has been filled
             *                     (i.e. the "numerator").
             * @return totalSize   The total size of the order that is either filled or
             *                     unfilled (i.e. the "denominator").
             */
            function getOrderStatus(
                bytes32 orderHash
            )
                external
                view
                returns (
                    bool isValidated,
                    bool isCancelled,
                    uint256 totalFilled,
                    uint256 totalSize
                );
            /**
             * @notice Retrieve the current counter for a given offerer.
             *
             * @param offerer The offerer in question.
             *
             * @return counter The current counter.
             */
            function getCounter(
                address offerer
            ) external view returns (uint256 counter);
            /**
             * @notice Retrieve configuration information for this contract.
             *
             * @return version           The contract version.
             * @return domainSeparator   The domain separator for this contract.
             * @return conduitController The conduit Controller set for this contract.
             */
            function information()
                external
                view
                returns (
                    string memory version,
                    bytes32 domainSeparator,
                    address conduitController
                );
            function getContractOffererNonce(
                address contractOfferer
            ) external view returns (uint256 nonce);
            /**
             * @notice Retrieve the name of this contract.
             *
             * @return contractName The name of this contract.
             */
            function name() external view returns (string memory contractName);
        }
        // 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.24;
        import {
            Side,
            ItemType,
            OrderType
        } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            ConsiderationItem,
            CriteriaResolver,
            Execution,
            Fulfillment,
            FulfillmentComponent,
            OfferItem,
            OrderParameters,
            ReceivedItem
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { OrderFulfiller } from "./OrderFulfiller.sol";
        import { FulfillmentApplier } from "./FulfillmentApplier.sol";
        import {
            _revertConsiderationNotMet,
            _revertInvalidNativeOfferItem,
            _revertNoSpecifiedOrdersAvailable
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            Error_selector_offset,
            InsufficientNativeTokensSupplied_error_selector,
            InsufficientNativeTokensSupplied_error_length
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        import {
            AccumulatorDisarmed,
            ConsiderationItem_recipient_offset,
            Execution_offerer_offset,
            NonMatchSelector_InvalidErrorValue,
            NonMatchSelector_MagicMask,
            OneWord,
            OneWordShift,
            OrdersMatchedTopic0,
            ReceivedItem_amount_offset,
            ReceivedItem_recipient_offset,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            MemoryPointer,
            MemoryPointerLib,
            ZeroSlotPtr
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        /**
         * @title OrderCombiner
         * @author 0age
         * @notice OrderCombiner contains logic for fulfilling combinations of orders,
         *         either by matching offer items to consideration items or by
         *         fulfilling orders where available.
         */
        contract OrderCombiner is OrderFulfiller, FulfillmentApplier {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) OrderFulfiller(conduitController) {}
            /**
             * @notice Internal function to attempt to fill a group of orders, fully or
             *         partially, with an arbitrary number of items for offer and
             *         consideration per order alongside criteria resolvers containing
             *         specific token identifiers and associated proofs. Any order that
             *         is not currently active, has already been fully filled, or has
             *         been cancelled will be omitted. Remaining offer and consideration
             *         items will then be aggregated where possible as indicated by the
             *         supplied offer and consideration component arrays and aggregated
             *         items will be transferred to the fulfiller or to each intended
             *         recipient, respectively. Note that a failing item transfer or an
             *         issue with order formatting will cause the entire batch to fail.
             *
             * @param advancedOrders            The orders to fulfill along with the
             *                                  fraction of those orders to attempt to
             *                                  fill. Note that both the offerer and the
             *                                  fulfiller must first approve this
             *                                  contract (or a conduit if indicated by
             *                                  the order) to transfer any relevant
             *                                  tokens on their behalf and that
             *                                  contracts must implement
             *                                  `onERC1155Received` in order to receive
             *                                  ERC1155 tokens as consideration. Also
             *                                  note that all offer and consideration
             *                                  components must have no remainder after
             *                                  multiplication of the respective amount
             *                                  with the supplied fraction for an
             *                                  order's partial fill amount to be
             *                                  considered valid.
             * @param criteriaResolvers         An array where each element contains a
             *                                  reference to a specific offer or
             *                                  consideration, a token identifier, and a
             *                                  proof that the supplied token identifier
             *                                  is contained in the merkle root held by
             *                                  the item in question's criteria element.
             *                                  Note that an empty criteria indicates
             *                                  that any (transferable) token
             *                                  identifier on the token in question is
             *                                  valid and that no associated proof needs
             *                                  to be supplied.
             * @param offerFulfillments         An array of FulfillmentComponent arrays
             *                                  indicating which offer items to attempt
             *                                  to aggregate when preparing executions.
             * @param considerationFulfillments An array of FulfillmentComponent arrays
             *                                  indicating which consideration items to
             *                                  attempt to aggregate when preparing
             *                                  executions.
             * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
             *                                  if any, to source the fulfiller's token
             *                                  approvals from. The zero hash signifies
             *                                  that no conduit should be used (and
             *                                  direct approvals set on Consideration).
             * @param recipient                 The intended recipient for all received
             *                                  items.
             * @param maximumFulfilled          The maximum number of orders to fulfill.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders.
             */
            function _fulfillAvailableAdvancedOrders(
                AdvancedOrder[] memory advancedOrders,
                CriteriaResolver[] memory criteriaResolvers,
                FulfillmentComponent[][] memory offerFulfillments,
                FulfillmentComponent[][] memory considerationFulfillments,
                bytes32 fulfillerConduitKey,
                address recipient,
                uint256 maximumFulfilled
            )
                internal
                returns (
                    bool[] memory /* availableOrders */,
                    Execution[] memory /* executions */
                )
            {
                // Create a `false` boolean variable to indicate that invalid orders
                // should NOT revert. Does not use a constant to avoid function
                // specialization in solc that would increase contract size.
                bool revertOnInvalid = _runTimeConstantFalse();
                // Validate orders, apply amounts, & determine if they use conduits.
                (
                    bytes32[] memory orderHashes,
                    bool containsNonOpen
                ) = _validateOrdersAndPrepareToFulfill(
                        advancedOrders,
                        criteriaResolvers,
                        revertOnInvalid,
                        maximumFulfilled,
                        recipient
                    );
                // Aggregate used offer and consideration items and execute transfers.
                return
                    _executeAvailableFulfillments(
                        advancedOrders,
                        offerFulfillments,
                        considerationFulfillments,
                        fulfillerConduitKey,
                        recipient,
                        orderHashes,
                        containsNonOpen
                    );
            }
            /**
             * @dev Internal function to validate a group of orders, update their
             *      statuses, reduce amounts by their previously filled fractions, apply
             *      criteria resolvers, and emit OrderFulfilled events. Note that this
             *      function needs to be called before
             *      _aggregateValidFulfillmentConsiderationItems to set the memory
             *      layout that _aggregateValidFulfillmentConsiderationItems depends on.
             *
             * @param advancedOrders    The advanced orders to validate and reduce by
             *                          their previously filled amounts.
             * @param criteriaResolvers An array where each element contains a reference
             *                          to a specific order as well as that order's
             *                          offer or consideration, a token identifier, and
             *                          a proof that the supplied token identifier is
             *                          contained in the order's merkle root. Note that
             *                          a root of zero indicates that any transferable
             *                          token identifier is valid and that no proof
             *                          needs to be supplied.
             * @param revertOnInvalid   A boolean indicating whether to revert on any
             *                          order being invalid; setting this to false will
             *                          instead cause the invalid order to be skipped.
             * @param maximumFulfilled  The maximum number of orders to fulfill.
             * @param recipient         The intended recipient for all items that do not
             *                          already have a designated recipient and are not
             *                          already used as part of a provided fulfillment.
             *
             * @return orderHashes     The hashes of the orders being fulfilled.
             * @return containsNonOpen A boolean indicating whether any restricted or
             *                         contract orders are present within the provided
             *                         array of advanced orders.
             */
            function _validateOrdersAndPrepareToFulfill(
                AdvancedOrder[] memory advancedOrders,
                CriteriaResolver[] memory criteriaResolvers,
                bool revertOnInvalid,
                uint256 maximumFulfilled,
                address recipient
            ) internal returns (bytes32[] memory orderHashes, bool containsNonOpen) {
                // Ensure this function cannot be triggered during a reentrant call.
                _setReentrancyGuard(true); // Native tokens accepted during execution.
                // Declare "terminal memory offset" variable for use in efficient loops.
                uint256 terminalMemoryOffset;
                {
                    // Declare an error buffer indicating status of any native offer
                    // items. Native tokens may only be provided as part of contract
                    // orders or when fulfilling via matchOrders or matchAdvancedOrders;
                    // throw if bits indicating the conditions aren't met have been set.
                    uint256 invalidNativeOfferItemErrorBuffer;
                    // Use assembly to set the value for the second bit of error buffer.
                    assembly {
                        /**
                         * Use the 231st bit of the error buffer to indicate whether the
                         * current function is not matchAdvancedOrders or matchOrders.
                         *
                         * sig                                func
                         * -------------------------------------------------------------
                         * 1010100000010111010001000 0 000100 matchOrders
                         * 1111001011010001001010110 0 010010 matchAdvancedOrders
                         * 1110110110011000101001010 1 110100 fulfillAvailableOrders
                         * 1000011100100000000110110 1 000001 fulfillAvailableAdvanced
                         *                           ^ 7th bit
                         */
                        invalidNativeOfferItemErrorBuffer := and(
                            NonMatchSelector_MagicMask,
                            calldataload(0)
                        )
                    }
                    unchecked {
                        // Read length of orders array and place on the stack.
                        uint256 totalOrders = advancedOrders.length;
                        // Track the order hash for each order being fulfilled.
                        orderHashes = new bytes32[](totalOrders);
                        // Determine the memory offset to terminate on during loops.
                        terminalMemoryOffset = (totalOrders + 1) << OneWordShift;
                    }
                    // Skip overflow checks as for loops are indexed starting at zero.
                    unchecked {
                        // Declare variable to track if order is not a contract order.
                        bool isNonContract;
                        // Iterate over each order.
                        for (
                            uint256 i = OneWord;
                            i < terminalMemoryOffset;
                            i += OneWord
                        ) {
                            // Retrieve order via pointer to bypass out-of-range check &
                            // cast function to avoid additional memory allocation.
                            AdvancedOrder memory advancedOrder = (
                                _getReadAdvancedOrderByOffset()(advancedOrders, i)
                            );
                            // Validate it, update status, & determine fraction to fill.
                            (
                                bytes32 orderHash,
                                uint256 numerator,
                                uint256 denominator
                            ) = _validateOrder(advancedOrder, revertOnInvalid);
                            // Update the numerator on the order in question.
                            advancedOrder.numerator = uint120(numerator);
                            // Do not track hash or adjust prices if order is skipped.
                            if (numerator == 0) {
                                // Continue iterating through the remaining orders.
                                continue;
                            }
                            // Update the denominator on the order in question.
                            advancedOrder.denominator = uint120(denominator);
                            // Otherwise, track the order hash in question.
                            assembly {
                                mstore(add(orderHashes, i), orderHash)
                            }
                            // Place the start time for the order on the stack.
                            uint256 startTime = advancedOrder.parameters.startTime;
                            // Place the end time for the order on the stack.
                            uint256 endTime = advancedOrder.parameters.endTime;
                            {
                                // Determine order type, used to check for eligibility
                                // for native token offer items as well as for presence
                                // of restricted and contract orders or non-open orders.
                                OrderType orderType = (
                                    advancedOrder.parameters.orderType
                                );
                                // Utilize assembly to efficiently check order types.
                                // Note these checks expect that there are no order
                                // types beyond current set (0-4) and will need to be
                                // modified if more order types are added.
                                assembly {
                                    // Assign the variable indicating if the order is
                                    // not a contract order.
                                    isNonContract := lt(orderType, 4)
                                    // Update the variable indicating if order is not an
                                    // open order & keep set if it has been set already.
                                    containsNonOpen := or(
                                        containsNonOpen,
                                        gt(orderType, 1)
                                    )
                                }
                            }
                            // Retrieve array of offer items for the order in question.
                            OfferItem[] memory offer = advancedOrder.parameters.offer;
                            // Read length of offer array and place on the stack.
                            uint256 totalOfferItems = offer.length;
                            // Iterate over each offer item on the order.
                            for (uint256 j = 0; j < totalOfferItems; ++j) {
                                // Retrieve the offer item.
                                OfferItem memory offerItem = offer[j];
                                // If the offer item is for the native token and the
                                // order type is not a contract order type, set the
                                // first bit of the error buffer to true.
                                assembly {
                                    invalidNativeOfferItemErrorBuffer := or(
                                        invalidNativeOfferItemErrorBuffer,
                                        lt(mload(offerItem), isNonContract)
                                    )
                                }
                                // Apply order fill fraction to offer item end amount.
                                uint256 endAmount = _getFraction(
                                    numerator,
                                    denominator,
                                    offerItem.endAmount
                                );
                                // Reuse same fraction if start & end amounts are equal.
                                if (offerItem.startAmount == offerItem.endAmount) {
                                    // Apply derived amount to both start & end amount.
                                    offerItem.startAmount = endAmount;
                                } else {
                                    // Apply order fill fraction to item start amount.
                                    offerItem.startAmount = _getFraction(
                                        numerator,
                                        denominator,
                                        offerItem.startAmount
                                    );
                                }
                                // Adjust offer amount using current time; round down.
                                uint256 currentAmount = _locateCurrentAmount(
                                    offerItem.startAmount,
                                    endAmount,
                                    startTime,
                                    endTime,
                                    _runTimeConstantFalse() // round down
                                );
                                // Update amounts in memory to match the current amount.
                                // Note the end amount is used to track spent amounts.
                                offerItem.startAmount = currentAmount;
                                offerItem.endAmount = currentAmount;
                            }
                            // Retrieve consideration item array for order in question.
                            ConsiderationItem[] memory consideration = (
                                advancedOrder.parameters.consideration
                            );
                            // Read length of consideration array and place on stack.
                            uint256 totalConsiderationItems = consideration.length;
                            // Iterate over each consideration item on the order.
                            for (uint256 j = 0; j < totalConsiderationItems; ++j) {
                                // Retrieve the consideration item.
                                ConsiderationItem memory considerationItem = (
                                    consideration[j]
                                );
                                // Apply fraction to consideration item end amount.
                                uint256 endAmount = _getFraction(
                                    numerator,
                                    denominator,
                                    considerationItem.endAmount
                                );
                                // Reuse same fraction if start & end amounts are equal.
                                if (
                                    considerationItem.startAmount ==
                                    considerationItem.endAmount
                                ) {
                                    // Apply derived amount to both start & end amount.
                                    considerationItem.startAmount = endAmount;
                                } else {
                                    // Apply fraction to item start amount.
                                    considerationItem.startAmount = _getFraction(
                                        numerator,
                                        denominator,
                                        considerationItem.startAmount
                                    );
                                }
                                // Adjust amount using current time; round up.
                                uint256 currentAmount = (
                                    _locateCurrentAmount(
                                        considerationItem.startAmount,
                                        endAmount,
                                        startTime,
                                        endTime,
                                        _runTimeConstantTrue() // round up
                                    )
                                );
                                // Set the start amount as equal to the current amount.
                                considerationItem.startAmount = currentAmount;
                                // Utilize assembly to manually "shift" the recipient
                                // value, then copy the start amount to the recipient.
                                // Note that this sets up the memory layout that is
                                // subsequently relied upon by
                                // _aggregateValidFulfillmentConsiderationItems as well
                                // as during comparison to generated contract orders.
                                assembly {
                                    // Derive pointer to the recipient using the item
                                    // pointer along with the offset to the recipient.
                                    let considerationItemRecipientPtr := add(
                                        considerationItem,
                                        ConsiderationItem_recipient_offset
                                    )
                                    // Write recipient to endAmount, as endAmount is not
                                    // used from this point on and can be repurposed to
                                    // fit the layout of a ReceivedItem.
                                    mstore(
                                        add(
                                            considerationItem,
                                            // Note that this value used to be endAmount
                                            ReceivedItem_recipient_offset
                                        ),
                                        mload(considerationItemRecipientPtr)
                                    )
                                    // Write startAmount to recipient, as recipient is
                                    // not used from this point on and can be repurposed
                                    // to track received amounts.
                                    mstore(considerationItemRecipientPtr, currentAmount)
                                }
                            }
                        }
                    }
                    // If the first bit is set, a native offer item was encountered on
                    // an order that is not a contract order. If the 231st bit is set in
                    // the error buffer, the current function is not matchOrders or
                    // matchAdvancedOrders. If the value is 1 + (1 << 230), then both
                    // 1st and 231st bits were set; in that case, revert with an error.
                    if (
                        invalidNativeOfferItemErrorBuffer ==
                        NonMatchSelector_InvalidErrorValue
                    ) {
                        _revertInvalidNativeOfferItem();
                    }
                }
                // Apply criteria resolvers to each order as applicable.
                _applyCriteriaResolvers(advancedOrders, criteriaResolvers);
                // Iterate over each order to check authorization status (for restricted
                // orders), generate orders (for contract orders), and emit events (for
                // all available orders) signifying that they have been fulfilled.
                // Skip overflow checks as all for loops are indexed starting at zero.
                unchecked {
                    // Declare stack variable outside of the loop to track order hash.
                    bytes32 orderHash;
                    // Track whether any orders are still available for fulfillment.
                    bool someOrderAvailable = false;
                    // Iterate over each order.
                    for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) {
                        // Retrieve order hash, bypassing out-of-range check.
                        assembly {
                            orderHash := mload(add(orderHashes, i))
                        }
                        // Do not emit an event if no order hash is present.
                        if (orderHash == bytes32(0)) {
                            continue;
                        }
                        // Retrieve order using pointer libraries to bypass out-of-range
                        // check & cast function to avoid additional memory allocation.
                        AdvancedOrder memory advancedOrder = (
                            _getReadAdvancedOrderByOffset()(advancedOrders, i)
                        );
                        // Determine if max number orders have already been fulfilled.
                        if (maximumFulfilled == 0) {
                            // If so, set the order hash to zero.
                            assembly {
                                mstore(add(orderHashes, i), 0)
                            }
                            // Set the numerator to zero to signal to skip the order.
                            advancedOrder.numerator = 0;
                            // Continue iterating through the remaining orders.
                            continue;
                        }
                        // Handle final checks and status updates based on order type.
                        if (advancedOrder.parameters.orderType != OrderType.CONTRACT) {
                            // Check authorization for restricted orders.
                            if (
                                !_checkRestrictedAdvancedOrderAuthorization(
                                    advancedOrder,
                                    orderHashes,
                                    orderHash,
                                    (i >> OneWordShift) - 1,
                                    revertOnInvalid
                                )
                            ) {
                                // If authorization check fails, set order hash to zero.
                                assembly {
                                    mstore(add(orderHashes, i), 0)
                                }
                                // Set numerator to zero to signal to skip the order.
                                advancedOrder.numerator = 0;
                                // Continue iterating through the remaining orders.
                                continue;
                            }
                            // Update status as long as some fraction is available.
                            if (
                                !_updateStatus(
                                    orderHash,
                                    advancedOrder.numerator,
                                    advancedOrder.denominator,
                                    _revertOnFailedUpdate(
                                        advancedOrder.parameters,
                                        revertOnInvalid
                                    )
                                )
                            ) {
                                // If status update fails, set the order hash to zero.
                                assembly {
                                    mstore(add(orderHashes, i), 0)
                                }
                                // Set numerator to zero to signal to skip the order.
                                advancedOrder.numerator = 0;
                                // Continue iterating through the remaining orders.
                                continue;
                            }
                        } else {
                            // Return the generated order based on the order params and
                            // the provided extra data. If revertOnInvalid is true, the
                            // function will revert if the input is invalid.
                            orderHash = _getGeneratedOrder(
                                advancedOrder.parameters,
                                advancedOrder.extraData,
                                revertOnInvalid
                            );
                            // Write the derived order hash to the order hashes array.
                            assembly {
                                mstore(add(orderHashes, i), orderHash)
                            }
                            // Handle invalid orders, indicated by a zero order hash.
                            if (orderHash == bytes32(0)) {
                                // Set numerator to zero to signal to skip the order.
                                advancedOrder.numerator = 0;
                                // Continue iterating through the remaining orders.
                                continue;
                            }
                        }
                        // Decrement the number of fulfilled orders.
                        // Skip underflow check as the condition before
                        // implies that maximumFulfilled > 0.
                        --maximumFulfilled;
                        // Retrieve parameters for the order in question.
                        OrderParameters memory orderParameters = (
                            advancedOrder.parameters
                        );
                        // Emit an OrderFulfilled event.
                        _emitOrderFulfilledEvent(
                            orderHash,
                            orderParameters.offerer,
                            orderParameters.zone,
                            recipient,
                            orderParameters.offer,
                            orderParameters.consideration
                        );
                        // Set the flag indicating that some order is available.
                        someOrderAvailable = true;
                    }
                    // Revert if no orders are available.
                    if (!someOrderAvailable) {
                        _revertNoSpecifiedOrdersAvailable();
                    }
                }
            }
            /**
             * @dev Internal function to fulfill a group of validated orders, fully or
             *      partially, with an arbitrary number of items for offer and
             *      consideration per order and to execute transfers. Any order that is
             *      not currently active, has already been fully filled, or has been
             *      cancelled will be omitted. Remaining offer and consideration items
             *      will then be aggregated where possible as indicated by the supplied
             *      offer and consideration component arrays and aggregated items will
             *      be transferred to the fulfiller or to each intended recipient,
             *      respectively. Note that a failing item transfer or an issue with
             *      order formatting will cause the entire batch to fail.
             *
             * @param advancedOrders            The orders to fulfill along with the
             *                                  fraction of those orders to attempt to
             *                                  fill. Note that both the offerer and the
             *                                  fulfiller must first approve this
             *                                  contract (or the conduit if indicated by
             *                                  the order) to transfer any relevant
             *                                  tokens on their behalf and that
             *                                  contracts must implement
             *                                  `onERC1155Received` in order to receive
             *                                  ERC1155 tokens as consideration. Also
             *                                  note that all offer and consideration
             *                                  components must have no remainder after
             *                                  multiplication of the respective amount
             *                                  with the supplied fraction for an
             *                                  order's partial fill amount to be
             *                                  considered valid.
             * @param offerFulfillments         An array of FulfillmentComponent arrays
             *                                  indicating which offer items to attempt
             *                                  to aggregate when preparing executions.
             * @param considerationFulfillments An array of FulfillmentComponent arrays
             *                                  indicating which consideration items to
             *                                  attempt to aggregate when preparing
             *                                  executions.
             * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
             *                                  if any, to source the fulfiller's token
             *                                  approvals from. The zero hash signifies
             *                                  that no conduit should be used, with
             *                                  direct approvals set on Consideration.
             * @param recipient                 The intended recipient for all items
             *                                  that do not already have a designated
             *                                  recipient and are not already used as
             *                                  part of a provided fulfillment.
             * @param orderHashes               An array of order hashes for each order.
             * @param containsNonOpen           A boolean indicating whether any
             *                                  restricted or contract orders are
             *                                  present within the provided array of
             *                                  advanced orders.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             * @return executions      An array of elements indicating the sequence of
             *                         transfers performed as part of matching the given
             *                         orders.
             */
            function _executeAvailableFulfillments(
                AdvancedOrder[] memory advancedOrders,
                FulfillmentComponent[][] memory offerFulfillments,
                FulfillmentComponent[][] memory considerationFulfillments,
                bytes32 fulfillerConduitKey,
                address recipient,
                bytes32[] memory orderHashes,
                bool containsNonOpen
            )
                internal
                returns (bool[] memory availableOrders, Execution[] memory executions)
            {
                // Retrieve length of offer fulfillments array and place on the stack.
                uint256 totalOfferFulfillments = offerFulfillments.length;
                // Retrieve length of consideration fulfillments array & place on stack.
                uint256 totalConsiderationFulfillments = (
                    considerationFulfillments.length
                );
                // Allocate an execution for each offer and consideration fulfillment.
                executions = new Execution[](
                    totalOfferFulfillments + totalConsiderationFulfillments
                );
                // Skip overflow checks as all for loops are indexed starting at zero.
                unchecked {
                    // Iterate over each offer fulfillment.
                    for (uint256 i = 0; i < totalOfferFulfillments; ++i) {
                        // Derive aggregated execution corresponding with fulfillment
                        // and assign it to the executions array.
                        executions[i] = _aggregateAvailable(
                            advancedOrders,
                            Side.OFFER,
                            offerFulfillments[i],
                            fulfillerConduitKey,
                            recipient
                        );
                    }
                    // Iterate over each consideration fulfillment.
                    for (uint256 i = 0; i < totalConsiderationFulfillments; ++i) {
                        // Derive aggregated execution corresponding with fulfillment
                        // and assign it to the executions array.
                        executions[i + totalOfferFulfillments] = _aggregateAvailable(
                            advancedOrders,
                            Side.CONSIDERATION,
                            considerationFulfillments[i],
                            fulfillerConduitKey,
                            address(0) // unused
                        );
                    }
                }
                // Perform final checks and return.
                availableOrders = _performFinalChecksAndExecuteOrders(
                    advancedOrders,
                    executions,
                    orderHashes,
                    recipient,
                    containsNonOpen
                );
                return (availableOrders, executions);
            }
            /**
             * @dev Internal function to perform a final check that each consideration
             *      item for an arbitrary number of fulfilled orders has been met and to
             *      trigger associated executions, transferring the respective items.
             *
             * @param advancedOrders  The orders to check and perform executions for.
             * @param executions      An array of elements indicating the sequence of
             *                        transfers to perform when fulfilling the given
             *                        orders.
             * @param orderHashes     An array of order hashes for each order.
             * @param recipient       The intended recipient for all items that do not
             *                        already have a designated recipient and are not
             *                        used as part of a provided fulfillment.
             * @param containsNonOpen A boolean indicating whether any restricted or
             *                        contract orders are present within the provided
             *                        array of advanced orders.
             *
             * @return availableOrders An array of booleans indicating if each order
             *                         with an index corresponding to the index of the
             *                         returned boolean was fulfillable or not.
             */
            function _performFinalChecksAndExecuteOrders(
                AdvancedOrder[] memory advancedOrders,
                Execution[] memory executions,
                bytes32[] memory orderHashes,
                address recipient,
                bool containsNonOpen
            ) internal returns (bool[] memory /* availableOrders */) {
                // Retrieve the length of the advanced orders array and place on stack.
                uint256 totalOrders = advancedOrders.length;
                // Initialize array for tracking available orders.
                bool[] memory availableOrders = new bool[](totalOrders);
                // Initialize an accumulator array. From this point forward, no new
                // memory regions can be safely allocated until the accumulator is no
                // longer being utilized, as the accumulator operates in an open-ended
                // fashion from this memory pointer; existing memory may still be
                // accessed and modified, however.
                bytes memory accumulator = new bytes(AccumulatorDisarmed);
                // Skip overflow check: loop index & executions length are both bounded.
                unchecked {
                    // Determine the memory offset to terminate on during loops.
                    uint256 terminalMemoryOffset = ((executions.length + 1) <<
                        OneWordShift);
                    // Iterate over each execution.
                    for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) {
                        // Get execution using pointer libraries to bypass out-of-range
                        // check & cast function to avoid additional memory allocation.
                        Execution memory execution = (
                            _getReadExecutionByOffset()(executions, i)
                        );
                        // Retrieve the associated received item and amount.
                        ReceivedItem memory item = execution.item;
                        uint256 amount = item.amount;
                        // Transfer the item specified by the execution as long as the
                        // execution is not a zero-amount execution (which can occur if
                        // the corresponding fulfillment contained only items on orders
                        // that are unavailable or are out of range of the respective
                        // item array).
                        if (amount != 0) {
                            // Utilize assembly to check for native token balance.
                            assembly {
                                // Ensure a sufficient native balance if relevant.
                                if and(
                                    iszero(mload(item)), // itemType == ItemType.NATIVE
                                    // item.amount > address(this).balance
                                    gt(amount, selfbalance())
                                ) {
                                    // Store left-padded selector with push4,
                                    // mem[28:32] = selector
                                    mstore(
                                        0,
                                        InsufficientNativeTokensSupplied_error_selector
                                    )
                                    // revert(abi.encodeWithSignature(
                                    //   "InsufficientNativeTokensSupplied()"
                                    // ))
                                    revert(
                                        Error_selector_offset,
                                        InsufficientNativeTokensSupplied_error_length
                                    )
                                }
                            }
                            // Transfer the item specified by the execution.
                            _transfer(
                                item,
                                execution.offerer,
                                execution.conduitKey,
                                accumulator
                            );
                        }
                    }
                }
                // Skip overflow checks as all for loops are indexed starting at zero.
                unchecked {
                    // Iterate over each order.
                    for (uint256 i = 0; i < totalOrders; ++i) {
                        // Retrieve the order in question.
                        AdvancedOrder memory advancedOrder = advancedOrders[i];
                        // Skip the order in question if not being not fulfilled.
                        if (advancedOrder.numerator == 0) {
                            // Explicitly set availableOrders at the given index to
                            // guard against the possibility of dirtied memory.
                            availableOrders[i] = false;
                            continue;
                        }
                        // Mark the order as available.
                        availableOrders[i] = true;
                        // Retrieve the order parameters.
                        OrderParameters memory parameters = advancedOrder.parameters;
                        {
                            // Retrieve offer items.
                            OfferItem[] memory offer = parameters.offer;
                            // Read length of offer array & place on the stack.
                            uint256 totalOfferItems = offer.length;
                            // Iterate over each offer item to restore it.
                            for (uint256 j = 0; j < totalOfferItems; ++j) {
                                // Retrieve the offer item in question.
                                OfferItem memory offerItem = offer[j];
                                // Transfer to recipient if unspent amount is not zero.
                                // Note that the transfer will not be reflected in the
                                // executions array.
                                if (offerItem.startAmount != 0) {
                                    // Replace endAmount parameter with the recipient to
                                    // make offerItem compatible with the ReceivedItem
                                    // input to _transfer & cache the original endAmount
                                    // so it can be restored after the transfer.
                                    uint256 originalEndAmount = (
                                        _replaceEndAmountWithRecipient(
                                            offerItem,
                                            recipient
                                        )
                                    );
                                    // Transfer excess offer item amount to recipient.
                                    _toOfferItemInput(_transfer)(
                                        offerItem,
                                        parameters.offerer,
                                        parameters.conduitKey,
                                        accumulator
                                    );
                                    // Restore the original endAmount in offerItem.
                                    assembly {
                                        mstore(
                                            add(
                                                offerItem,
                                                ReceivedItem_recipient_offset
                                            ),
                                            originalEndAmount
                                        )
                                    }
                                }
                                // Restore original amount on the offer item.
                                offerItem.startAmount = offerItem.endAmount;
                            }
                        }
                        {
                            // Read consideration items & ensure they are fulfilled.
                            ConsiderationItem[] memory consideration = (
                                parameters.consideration
                            );
                            // Read length of consideration array & place on stack.
                            uint256 totalConsiderationItems = consideration.length;
                            // Iterate over each consideration item.
                            for (uint256 j = 0; j < totalConsiderationItems; ++j) {
                                ConsiderationItem memory considerationItem = (
                                    consideration[j]
                                );
                                // Retrieve remaining amount on consideration item.
                                uint256 unmetAmount = considerationItem.startAmount;
                                // Revert if the remaining amount is not zero.
                                if (unmetAmount != 0) {
                                    _revertConsiderationNotMet(i, j, unmetAmount);
                                }
                                // Utilize assembly to restore the original value.
                                assembly {
                                    // Write recipient to startAmount.
                                    mstore(
                                        add(
                                            considerationItem,
                                            ReceivedItem_amount_offset
                                        ),
                                        mload(
                                            add(
                                                considerationItem,
                                                ConsiderationItem_recipient_offset
                                            )
                                        )
                                    )
                                }
                            }
                        }
                    }
                }
                // Trigger any accumulated transfers via call to the conduit.
                _triggerIfArmed(accumulator);
                // Determine whether any native token balance remains.
                uint256 remainingNativeTokenBalance;
                assembly {
                    remainingNativeTokenBalance := selfbalance()
                }
                // Return any remaining native token balance to the caller.
                if (remainingNativeTokenBalance != 0) {
                    _transferNativeTokens(
                        payable(msg.sender),
                        remainingNativeTokenBalance
                    );
                }
                // If any restricted or contract orders are present in the group of
                // orders being fulfilled, perform any validateOrder or ratifyOrder
                // calls after all executions and related transfers are complete.
                if (containsNonOpen) {
                    // Iterate over each order a second time.
                    for (uint256 i = 0; i < totalOrders; ) {
                        // Ensure the order in question is being fulfilled.
                        if (availableOrders[i]) {
                            // Check restricted orders and contract orders.
                            _assertRestrictedAdvancedOrderValidity(
                                advancedOrders[i],
                                orderHashes,
                                orderHashes[i]
                            );
                        }
                        // Skip overflow checks as for loop is indexed starting at zero.
                        unchecked {
                            ++i;
                        }
                    }
                }
                // Clear the reentrancy guard.
                _clearReentrancyGuard();
                // Return the array containing available orders.
                return availableOrders;
            }
            /**
             * @dev Internal function to emit an OrdersMatched event using the same
             *      memory region as the existing order hash array.
             *
             * @param orderHashes An array of order hashes to include as an argument for
             *                    the OrdersMatched event.
             */
            function _emitOrdersMatched(bytes32[] memory orderHashes) internal {
                assembly {
                    // Load the array length from memory.
                    let length := mload(orderHashes)
                    // Get the full size of the event data - one word for the offset,
                    // one for the array length and one per hash.
                    let dataSize := add(TwoWords, shl(OneWordShift, length))
                    // Get pointer to start of data, reusing word before array length
                    // for the offset.
                    let dataPointer := sub(orderHashes, OneWord)
                    // Cache the existing word in memory at the offset pointer.
                    let cache := mload(dataPointer)
                    // Write an offset of 32.
                    mstore(dataPointer, OneWord)
                    // Emit the OrdersMatched event.
                    log1(dataPointer, dataSize, OrdersMatchedTopic0)
                    // Restore the cached word.
                    mstore(dataPointer, cache)
                }
            }
            /**
             * @dev Internal function to match an arbitrary number of full or partial
             *      orders, each with an arbitrary number of items for offer and
             *      consideration, supplying criteria resolvers containing specific
             *      token identifiers and associated proofs as well as fulfillments
             *      allocating offer components to consideration components.
             *
             * @param advancedOrders    The advanced orders to match. Note that both the
             *                          offerer and fulfiller on each order must first
             *                          approve this contract (or their conduit if
             *                          indicated by the order) to transfer any relevant
             *                          tokens on their behalf and each consideration
             *                          recipient must implement `onERC1155Received` in
             *                          order to receive ERC1155 tokens. Also note that
             *                          the offer and consideration components for each
             *                          order must have no remainder after multiplying
             *                          the respective amount with the supplied fraction
             *                          in order for the group of partial fills to be
             *                          considered valid.
             * @param criteriaResolvers An array where each element contains a reference
             *                          to a specific order as well as that order's
             *                          offer or consideration, a token identifier, and
             *                          a proof that the supplied token identifier is
             *                          contained in the order's merkle root. Note that
             *                          an empty root indicates that any (transferable)
             *                          token identifier is valid and that no associated
             *                          proof needs to be supplied.
             * @param fulfillments      An array of elements allocating offer components
             *                          to consideration components. Note that each
             *                          consideration component must be fully met in
             *                          order for the match operation to be valid.
             * @param recipient         The intended recipient for all unspent offer
             *                          item amounts.
             *
             * @return executions An array of elements indicating the sequence of
             *                    transfers performed as part of matching the given
             *                    orders.
             */
            function _matchAdvancedOrders(
                AdvancedOrder[] memory advancedOrders,
                CriteriaResolver[] memory criteriaResolvers,
                Fulfillment[] memory fulfillments,
                address recipient
            ) internal returns (Execution[] memory /* executions */) {
                // Create a `true` boolean variable to indicate that invalid orders
                // should revert. Does not use a constant to avoid function
                // specialization in solc that would increase contract size.
                bool revertOnInvalid = _runTimeConstantTrue();
                // Validate orders, update order status, and determine item amounts.
                (
                    bytes32[] memory orderHashes,
                    bool containsNonOpen
                ) = _validateOrdersAndPrepareToFulfill(
                        advancedOrders,
                        criteriaResolvers,
                        revertOnInvalid,
                        advancedOrders.length,
                        recipient
                    );
                // Emit OrdersMatched event, providing an array of matched order hashes.
                _emitOrdersMatched(orderHashes);
                // Fulfill the orders using the supplied fulfillments and recipient.
                return
                    _fulfillAdvancedOrders(
                        advancedOrders,
                        fulfillments,
                        orderHashes,
                        recipient,
                        containsNonOpen
                    );
            }
            /**
             * @dev Internal function to fulfill an arbitrary number of orders, either
             *      full or partial, after validating, adjusting amounts, and applying
             *      criteria resolvers.
             *
             * @param advancedOrders  The orders to match, including a fraction to
             *                        attempt to fill for each order.
             * @param fulfillments    An array of elements allocating offer components
             *                        to consideration components. Note that the final
             *                        amount of each consideration component must be
             *                        zero for a match operation to be considered valid.
             * @param orderHashes     An array of order hashes for each order.
             * @param recipient       The intended recipient for all items that do not
             *                        already have a designated recipient and are not
             *                        used as part of a provided fulfillment.
             * @param containsNonOpen A boolean indicating whether any restricted or
             *                        contract orders are present within the provided
             *                        array of advanced orders.
             *
             * @return executions An array of elements indicating the sequence of
             *                    transfers performed as part of matching the given
             *                    orders.
             */
            function _fulfillAdvancedOrders(
                AdvancedOrder[] memory advancedOrders,
                Fulfillment[] memory fulfillments,
                bytes32[] memory orderHashes,
                address recipient,
                bool containsNonOpen
            ) internal returns (Execution[] memory executions) {
                // Retrieve fulfillments array length and place on the stack.
                uint256 totalFulfillments = fulfillments.length;
                // Allocate executions by fulfillment and apply them to each execution.
                executions = new Execution[](totalFulfillments);
                // Skip overflow checks as all for loops are indexed starting at zero.
                unchecked {
                    // Iterate over each fulfillment.
                    for (uint256 i = 0; i < totalFulfillments; ++i) {
                        /// Retrieve the fulfillment in question.
                        Fulfillment memory fulfillment = fulfillments[i];
                        // Derive the execution corresponding with the fulfillment and
                        // assign it to the executions array.
                        executions[i] = _applyFulfillment(
                            advancedOrders,
                            fulfillment.offerComponents,
                            fulfillment.considerationComponents,
                            i
                        );
                    }
                }
                // Perform final checks and execute orders.
                _performFinalChecksAndExecuteOrders(
                    advancedOrders,
                    executions,
                    orderHashes,
                    recipient,
                    containsNonOpen
                );
                // Return the executions array.
                return executions;
            }
            /**
             * @dev Internal view function to determine whether a status update failure
             *      should cause a revert or allow a skipped order. The call must revert
             *      if an `authorizeOrder` call has been successfully performed and the
             *      status update cannot be performed, regardless of whether the order
             *      could be otherwise marked as skipped. Note that a revert is not
             *      required on a failed update if the call originates from the zone, as
             *      no `authorizeOrder` call is performed in that case.
             *
             * @param orderParameters The order parameters in question.
             * @param revertOnInvalid A boolean indicating whether the call should
             *                        revert for non-restricted order types.
             *
             * @return revertOnFailedUpdate A boolean indicating whether the order
             *                              should revert on a failed status update.
             */
            function _revertOnFailedUpdate(
                OrderParameters memory orderParameters,
                bool revertOnInvalid
            ) internal view returns (bool revertOnFailedUpdate) {
                OrderType orderType = orderParameters.orderType;
                address zone = orderParameters.zone;
                assembly {
                    revertOnFailedUpdate := or(
                        revertOnInvalid,
                        and(gt(orderType, 1), iszero(eq(caller(), zone)))
                    )
                }
            }
        }
        // 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);
        MemoryPointer constant ZeroSlotPtr = MemoryPointer.wrap(0x60);
        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 pptrOffset(
                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 pptrOffset(
                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 pptrOffset(
                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
        pragma solidity ^0.8.13;
        /*
         * -------------------------- Disambiguation & Other Notes ---------------------
         *    - The term "head" is used as it is in the documentation for ABI encoding,
         *      but only in reference to dynamic types, i.e. it always refers to the
         *      offset or pointer to the body of a dynamic type. In calldata, the head
         *      is always an offset (relative to the parent object), while in memory,
         *      the head is always the pointer to the body. More information found here:
         *      https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding
         *        - Note that the length of an array is separate from and precedes the
         *          head of the array.
         *
         *    - The term "body" is used in place of the term "head" used in the ABI
         *      documentation. It refers to the start of the data for a dynamic type,
         *      e.g. the first word of a struct or the first word of the first element
         *      in an array.
         *
         *    - The term "pointer" is used to describe the absolute position of a value
         *      and never an offset relative to another value.
         *        - The suffix "_ptr" refers to a memory pointer.
         *        - The suffix "_cdPtr" refers to a calldata pointer.
         *
         *    - The term "offset" is used to describe the position of a value relative
         *      to some parent value. For example, OrderParameters_conduit_offset is the
         *      offset to the "conduit" value in the OrderParameters struct relative to
         *      the start of the body.
         *        - Note: Offsets are used to derive pointers.
         *
         *    - Some structs have pointers defined for all of their fields in this file.
         *      Lines which are commented out are fields that are not used in the
         *      codebase but have been left in for readability.
         */
        // Declare constants for name, version, and reentrancy sentinel values.
        // Name is right padded, so it touches the length which is left padded. This
        // enables writing both values at once. Length goes at byte 95 in memory, and
        // name fills bytes 96-109, so both values can be written left-padded to 77.
        uint256 constant NameLengthPtr = 0x4D;
        uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;
        uint256 constant information_version_offset = 0;
        uint256 constant information_version_cd_offset = 0x60;
        uint256 constant information_domainSeparator_offset = 0x20;
        uint256 constant information_conduitController_offset = 0x40;
        uint256 constant information_versionLengthPtr = 0x63;
        uint256 constant information_versionWithLength = 0x03312e36; // 1.6
        uint256 constant information_length = 0xa0;
        // uint256(uint32(bytes4(keccak256("_REENTRANCY_GUARD_SLOT"))))
        uint256 constant _REENTRANCY_GUARD_SLOT = 0x929eee14;
        /*
         *
         * --------------------------------------------------------------------------+
         * Opcode      | Mnemonic         | Stack               | Memory             |
         * --------------------------------------------------------------------------|
         * 60 0x02     | PUSH1 0x02       | 0x02                |                    |
         * 60 0x1e     | PUSH1 0x1e       | 0x1e 0x02           |                    |
         * 61 0x3d5c   | PUSH2 0x3d5c     | 0x3d5c 0x1e 0x02    |                    |
         * 3d          | RETURNDATASIZE   | 0 0x3d5c 0x1e 0x02  |                    |
         *                                                                           |
         * ::: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD ::: |
         * 52          | MSTORE           | 0x1e 0x02           | [0..0x20): 0x3d5c  |
         * f3          | RETURN           |                     | [0..0x20): 0x3d5c  |
         * --------------------------------------------------------------------------+
         */
        uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
        uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
        uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;
        uint256 constant _NOT_ENTERED_TSTORE = 0;
        uint256 constant _ENTERED_TSTORE = 1;
        uint256 constant _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_TSTORE = 2;
        uint256 constant _TSTORE_ENABLED_SSTORE = 0;
        uint256 constant _NOT_ENTERED_SSTORE = 1;
        uint256 constant _ENTERED_SSTORE = 2;
        uint256 constant _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_SSTORE = 3;
        uint256 constant Offset_fulfillAdvancedOrder_criteriaResolvers = 0x20;
        uint256 constant Offset_fulfillAvailableOrders_offerFulfillments = 0x20;
        uint256 constant Offset_fulfillAvailableOrders_considerationFulfillments = 0x40;
        uint256 constant Offset_fulfillAvailableAdvancedOrders_criteriaResolvers = 0x20;
        uint256 constant Offset_fulfillAvailableAdvancedOrders_offerFulfillments = 0x40;
        uint256 constant Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts =
            (0x60);
        uint256 constant Offset_matchOrders_fulfillments = 0x20;
        uint256 constant Offset_matchAdvancedOrders_criteriaResolvers = 0x20;
        uint256 constant Offset_matchAdvancedOrders_fulfillments = 0x40;
        // Common Offsets
        // Offsets for identically positioned fields shared by:
        // OfferItem, ConsiderationItem, SpentItem, ReceivedItem
        uint256 constant Selector_length = 0x4;
        uint256 constant Common_token_offset = 0x20;
        uint256 constant Common_identifier_offset = 0x40;
        uint256 constant Common_amount_offset = 0x60;
        uint256 constant Common_endAmount_offset = 0x80;
        uint256 constant SpentItem_size = 0x80;
        uint256 constant SpentItem_size_shift = 0x7;
        uint256 constant OfferItem_size = 0xa0;
        uint256 constant OfferItem_size_with_head_pointer = 0xc0;
        uint256 constant ReceivedItem_size_excluding_recipient = 0x80;
        uint256 constant ReceivedItem_size = 0xa0;
        uint256 constant ReceivedItem_amount_offset = 0x60;
        uint256 constant ReceivedItem_recipient_offset = 0x80;
        uint256 constant ReceivedItem_CommonParams_size = 0x60;
        uint256 constant ConsiderationItem_size = 0xc0;
        uint256 constant ConsiderationItem_size_with_head_pointer = 0xe0;
        uint256 constant ConsiderationItem_recipient_offset = 0xa0;
        // Store the same constant in an abbreviated format for a line length fix.
        uint256 constant ConsiderItem_recipient_offset = 0xa0;
        uint256 constant Execution_offerer_offset = 0x20;
        uint256 constant Execution_conduit_offset = 0x40;
        // uint256 constant OrderParameters_offerer_offset = 0x00;
        uint256 constant OrderParameters_zone_offset = 0x20;
        uint256 constant OrderParameters_offer_head_offset = 0x40;
        uint256 constant OrderParameters_consideration_head_offset = 0x60;
        // uint256 constant OrderParameters_orderType_offset = 0x80;
        uint256 constant OrderParameters_startTime_offset = 0xa0;
        uint256 constant OrderParameters_endTime_offset = 0xc0;
        uint256 constant OrderParameters_zoneHash_offset = 0xe0;
        uint256 constant OrderParameters_salt_offset = 0x100;
        uint256 constant OrderParameters_conduit_offset = 0x120;
        uint256 constant OrderParameters_counter_offset = 0x140;
        uint256 constant Fulfillment_itemIndex_offset = 0x20;
        uint256 constant AdvancedOrder_head_size = 0xa0;
        uint256 constant AdvancedOrder_numerator_offset = 0x20;
        uint256 constant AdvancedOrder_denominator_offset = 0x40;
        uint256 constant AdvancedOrder_signature_offset = 0x60;
        uint256 constant AdvancedOrder_extraData_offset = 0x80;
        uint256 constant OrderStatus_ValidatedAndNotCancelled = 1;
        uint256 constant OrderStatus_filledNumerator_offset = 0x10;
        uint256 constant OrderStatus_filledDenominator_offset = 0x88;
        uint256 constant OrderStatus_ValidatedAndNotCancelledAndFullyFilled = (
            0x0000000000000000000000000000010000000000000000000000000000010001
        );
        uint256 constant ThirtyOneBytes = 0x1f;
        uint256 constant OneWord = 0x20;
        uint256 constant TwoWords = 0x40;
        uint256 constant ThreeWords = 0x60;
        uint256 constant FourWords = 0x80;
        uint256 constant FiveWords = 0xa0;
        uint256 constant OneWordShift = 0x5;
        uint256 constant TwoWordsShift = 0x6;
        uint256 constant SixtyThreeBytes = 0x3f;
        uint256 constant OnlyFullWordMask = 0xffffffe0;
        uint256 constant FreeMemoryPointerSlot = 0x40;
        uint256 constant ZeroSlot = 0x60;
        uint256 constant DefaultFreeMemoryPointer = 0x80;
        uint256 constant Slot0x80 = 0x80;
        uint256 constant Slot0xA0 = 0xa0;
        uint256 constant BasicOrder_common_params_size = 0xa0;
        uint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;
        uint256 constant BasicOrder_receivedItemByteMap =
            (0x0000010102030000000000000000000000000000000000000000000000000000);
        uint256 constant BasicOrder_offeredItemByteMap =
            (0x0203020301010000000000000000000000000000000000000000000000000000);
        uint256 constant BasicOrder_consideration_offset_from_offer = 0xa0;
        bytes32 constant OrdersMatchedTopic0 =
            (0x4b9f2d36e1b4c93de62cc077b00b1a91d84b6c31b4a14e012718dcca230689e7);
        uint256 constant EIP712_Order_size = 0x180;
        uint256 constant EIP712_OfferItem_size = 0xc0;
        uint256 constant EIP712_ConsiderationItem_size = 0xe0;
        uint256 constant AdditionalRecipient_size = 0x40;
        uint256 constant AdditionalRecipient_size_shift = 0x6;
        uint256 constant EIP712_DomainSeparator_offset = 0x02;
        uint256 constant EIP712_OrderHash_offset = 0x22;
        uint256 constant EIP712_DigestPayload_size = 0x42;
        uint256 constant EIP712_domainData_nameHash_offset = 0x20;
        uint256 constant EIP712_domainData_versionHash_offset = 0x40;
        uint256 constant EIP712_domainData_chainId_offset = 0x60;
        uint256 constant EIP712_domainData_verifyingContract_offset = 0x80;
        uint256 constant EIP712_domainData_size = 0xa0;
        // Minimum BulkOrder proof size: 64 bytes for signature + 3 for key + 32 for 1
        // sibling. Maximum BulkOrder proof size: 65 bytes for signature + 3 for key +
        // 768 for 24 siblings.
        uint256 constant BulkOrderProof_minSize = 0x63;
        uint256 constant BulkOrderProof_rangeSize = 0x2e2;
        uint256 constant BulkOrderProof_lengthAdjustmentBeforeMask = 0x1d;
        uint256 constant BulkOrderProof_lengthRangeAfterMask = 0x2;
        uint256 constant BulkOrderProof_keyShift = 0xe8;
        uint256 constant BulkOrderProof_keySize = 0x3;
        uint256 constant BulkOrder_Typehash_Height_One =
            (0x3ca2711d29384747a8f61d60aad3c450405f7aaff5613541dee28df2d6986d32);
        uint256 constant BulkOrder_Typehash_Height_Two =
            (0xbf8e29b89f29ed9b529c154a63038ffca562f8d7cd1e2545dda53a1b582dde30);
        uint256 constant BulkOrder_Typehash_Height_Three =
            (0x53c6f6856e13104584dd0797ca2b2779202dc2597c6066a42e0d8fe990b0024d);
        uint256 constant BulkOrder_Typehash_Height_Four =
            (0xa02eb7ff164c884e5e2c336dc85f81c6a93329d8e9adf214b32729b894de2af1);
        uint256 constant BulkOrder_Typehash_Height_Five =
            (0x39c9d33c18e050dda0aeb9a8086fb16fc12d5d64536780e1da7405a800b0b9f6);
        uint256 constant BulkOrder_Typehash_Height_Six =
            (0x1c19f71958cdd8f081b4c31f7caf5c010b29d12950be2fa1c95070dc47e30b55);
        uint256 constant BulkOrder_Typehash_Height_Seven =
            (0xca74fab2fece9a1d58234a274220ad05ca096a92ef6a1ca1750b9d90c948955c);
        uint256 constant BulkOrder_Typehash_Height_Eight =
            (0x7ff98d9d4e55d876c5cfac10b43c04039522f3ddfb0ea9bfe70c68cfb5c7cc14);
        uint256 constant BulkOrder_Typehash_Height_Nine =
            (0xbed7be92d41c56f9e59ac7a6272185299b815ddfabc3f25deb51fe55fe2f9e8a);
        uint256 constant BulkOrder_Typehash_Height_Ten =
            (0xd1d97d1ef5eaa37a4ee5fbf234e6f6d64eb511eb562221cd7edfbdde0848da05);
        uint256 constant BulkOrder_Typehash_Height_Eleven =
            (0x896c3f349c4da741c19b37fec49ed2e44d738e775a21d9c9860a69d67a3dae53);
        uint256 constant BulkOrder_Typehash_Height_Twelve =
            (0xbb98d87cc12922b83759626c5f07d72266da9702d19ffad6a514c73a89002f5f);
        uint256 constant BulkOrder_Typehash_Height_Thirteen =
            (0xe6ae19322608dd1f8a8d56aab48ed9c28be489b689f4b6c91268563efc85f20e);
        uint256 constant BulkOrder_Typehash_Height_Fourteen =
            (0x6b5b04cbae4fcb1a9d78e7b2dfc51a36933d023cf6e347e03d517b472a852590);
        uint256 constant BulkOrder_Typehash_Height_Fifteen =
            (0xd1eb68309202b7106b891e109739dbbd334a1817fe5d6202c939e75cf5e35ca9);
        uint256 constant BulkOrder_Typehash_Height_Sixteen =
            (0x1da3eed3ecef6ebaa6e5023c057ec2c75150693fd0dac5c90f4a142f9879fde8);
        uint256 constant BulkOrder_Typehash_Height_Seventeen =
            (0xeee9a1392aa395c7002308119a58f2582777a75e54e0c1d5d5437bd2e8bf6222);
        uint256 constant BulkOrder_Typehash_Height_Eighteen =
            (0xc3939feff011e53ab8c35ca3370aad54c5df1fc2938cd62543174fa6e7d85877);
        uint256 constant BulkOrder_Typehash_Height_Nineteen =
            (0x0efca7572ac20f5ae84db0e2940674f7eca0a4726fa1060ffc2d18cef54b203d);
        uint256 constant BulkOrder_Typehash_Height_Twenty =
            (0x5a4f867d3d458dabecad65f6201ceeaba0096df2d0c491cc32e6ea4e64350017);
        uint256 constant BulkOrder_Typehash_Height_TwentyOne =
            (0x80987079d291feebf21c2230e69add0f283cee0b8be492ca8050b4185a2ff719);
        uint256 constant BulkOrder_Typehash_Height_TwentyTwo =
            (0x3bd8cff538aba49a9c374c806d277181e9651624b3e31111bc0624574f8bca1d);
        uint256 constant BulkOrder_Typehash_Height_TwentyThree =
            (0x5d6a3f098a0bc373f808c619b1bb4028208721b3c4f8d6bc8a874d659814eb76);
        uint256 constant BulkOrder_Typehash_Height_TwentyFour =
            (0x1d51df90cba8de7637ca3e8fe1e3511d1dc2f23487d05dbdecb781860c21ac1c);
        uint256 constant receivedItemsHash_ptr = 0x60;
        /*
         *  Memory layout in _prepareBasicFulfillmentFromCalldata of
         *  data for OrderFulfilled
         *
         *   event OrderFulfilled(
         *     bytes32 orderHash,
         *     address indexed offerer,
         *     address indexed zone,
         *     address fulfiller,
         *     SpentItem[] offer,
         *       > (itemType, token, id, amount)
         *     ReceivedItem[] consideration
         *       > (itemType, token, id, amount, recipient)
         *   )
         *
         *  - 0x00: orderHash
         *  - 0x20: fulfiller
         *  - 0x40: offer offset (0x80)
         *  - 0x60: consideration offset (0x120)
         *  - 0x80: offer.length (1)
         *  - 0xa0: offerItemType
         *  - 0xc0: offerToken
         *  - 0xe0: offerIdentifier
         *  - 0x100: offerAmount
         *  - 0x120: consideration.length (1 + additionalRecipients.length)
         *  - 0x140: considerationItemType
         *  - 0x160: considerationToken
         *  - 0x180: considerationIdentifier
         *  - 0x1a0: considerationAmount
         *  - 0x1c0: considerationRecipient
         *  - ...
         */
        // Minimum length of the OrderFulfilled event data.
        // Must be added to the size of the ReceivedItem array for additionalRecipients
        // (0xa0 * additionalRecipients.length) to calculate full size of the buffer.
        uint256 constant OrderFulfilled_baseSize = 0x1e0;
        uint256 constant OrderFulfilled_selector =
            (0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31);
        // Minimum offset in memory to OrderFulfilled event data.
        // Must be added to the size of the EIP712 hash array for additionalRecipients
        // (32 * additionalRecipients.length) to calculate the pointer to event data.
        uint256 constant OrderFulfilled_baseOffset = 0x180;
        uint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0;
        uint256 constant OrderFulfilled_offer_length_baseOffset = 0x200;
        uint256 constant OrderFulfilled_offer_length_offset_relativeTo_baseOffset = (
            0x80
        );
        uint256 constant OrderFulfilled_offer_itemType_offset_relativeTo_baseOffset = (
            0xa0
        );
        uint256 constant OrderFulfilled_offer_token_offset_relativeTo_baseOffset = 0xc0;
        // Related constants used for restricted order checks on basic orders.
        uint256 constant OrderFulfilled_baseDataSize = 0x160;
        // uint256 constant ValidateOrder_offerDataOffset = 0x184;
        // uint256 constant RatifyOrder_offerDataOffset = 0xc4;
        // uint256 constant OrderFulfilled_orderHash_offset = 0x00;
        uint256 constant OrderFulfilled_fulfiller_offset = 0x20;
        uint256 constant OrderFulfilled_offer_head_offset = 0x40;
        uint256 constant OrderFulfilled_offer_body_offset = 0x80;
        uint256 constant OrderFulfilled_consideration_head_offset = 0x60;
        uint256 constant OrderFulfilled_consideration_body_offset = 0x120;
        /*
         * 3 memory slots/words for `authorizeOrder` and `validateOrder` calldata
         * to be used for tails of extra data (length 0) and order hashes (length 1)
         */
        uint256 constant OrderFulfilled_post_memory_region_reservedBytes = 0x60;
        /*
         * OrderFulfilled_offer_length_baseOffset - 12 * 0x20
         * we back up 12 words from where the `OrderFulfilled`'s data
         * for spent items start to be rewritten for `authorizeOrder`
         * and `validateOrder`. Let the reference pointer be `ptr`
         * pointing to the `OrderFulfilled`'s spent item array's length memory
         * position then we would have:
         *
         * ptr - 0x0180 : zero-padded calldata selector
         * ptr - 0x0160 : ZoneParameter's struct head (0x20)
         * ptr - 0x0140 : order hash
         * ptr - 0x0120 : fulfiller (msg.sender)
         * ptr - 0x0100 : offerer
         * ptr - 0x00e0 : spent items' head
         * ptr - 0x00c0 : received items' head
         * ptr - 0x00a0 : extra data / context head
         * ptr - 0x0080 : order hashes head
         * ptr - 0x0060 : start time
         * ptr - 0x0040 : end time
         * ptr - 0x0020 : zone hash
         * ptr - 0x0000 : offer.length (1)
         * ...
         *
         * Note that the padded calldata selector will be at minimum at the
         * 0x80 memory slot.
         */
        uint256 constant authorizeOrder_calldata_baseOffset = (
            OrderFulfilled_offer_length_baseOffset - 0x180
        );
        // BasicOrderParameters
        uint256 constant BasicOrder_parameters_cdPtr = 0x04;
        uint256 constant BasicOrder_considerationToken_cdPtr = 0x24;
        uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44;
        uint256 constant BasicOrder_considerationAmount_cdPtr = 0x64;
        uint256 constant BasicOrder_offerer_cdPtr = 0x84;
        uint256 constant BasicOrder_zone_cdPtr = 0xa4;
        uint256 constant BasicOrder_offerToken_cdPtr = 0xc4;
        uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4;
        uint256 constant BasicOrder_offerAmount_cdPtr = 0x104;
        uint256 constant BasicOrder_basicOrderParameters_cd_offset = 0x24;
        uint256 constant BasicOrder_basicOrderType_cdPtr = 0x124;
        uint256 constant BasicOrder_startTime_cdPtr = 0x144;
        uint256 constant BasicOrder_endTime_cdPtr = 0x164;
        // uint256 constant BasicOrder_zoneHash_cdPtr = 0x184;
        // uint256 constant BasicOrder_salt_cdPtr = 0x1a4;
        uint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4;
        uint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4;
        uint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204;
        uint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224;
        uint256 constant BasicOrder_signature_cdPtr = 0x244;
        uint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264;
        uint256 constant BasicOrder_addlRecipients_length_cdPtr = 0x264;
        uint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284;
        uint256 constant BasicOrder_parameters_ptr = 0x20;
        uint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values
        /*
         *  Memory layout in _prepareBasicFulfillmentFromCalldata of
         *  EIP712 data for ConsiderationItem
         *   - 0x80: ConsiderationItem EIP-712 typehash (constant)
         *   - 0xa0: itemType
         *   - 0xc0: token
         *   - 0xe0: identifier
         *   - 0x100: startAmount
         *   - 0x120: endAmount
         *   - 0x140: recipient
         */
        uint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr
        uint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0;
        uint256 constant BasicOrder_considerationItem_token_ptr = 0xc0;
        uint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0;
        uint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100;
        uint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120;
        // uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140;
        /*
         *  Memory layout in _prepareBasicFulfillmentFromCalldata of
         *  EIP712 data for OfferItem
         *   - 0x80:  OfferItem EIP-712 typehash (constant)
         *   - 0xa0:  itemType
         *   - 0xc0:  token
         *   - 0xe0:  identifier (reused for offeredItemsHash)
         *   - 0x100: startAmount
         *   - 0x120: endAmount
         */
        uint256 constant BasicOrder_offerItem_typeHash_ptr = 0x80;
        uint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0;
        uint256 constant BasicOrder_offerItem_token_ptr = 0xc0;
        // uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0;
        // uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100;
        uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120;
        /*
         *  Memory layout in _prepareBasicFulfillmentFromCalldata of
         *  EIP712 data for Order
         *   - 0x80:   Order EIP-712 typehash (constant)
         *   - 0xa0:   orderParameters.offerer
         *   - 0xc0:   orderParameters.zone
         *   - 0xe0:   keccak256(abi.encodePacked(offerHashes))
         *   - 0x100:  keccak256(abi.encodePacked(considerationHashes))
         *   - 0x120:  orderType
         *   - 0x140:  startTime
         *   - 0x160:  endTime
         *   - 0x180:  zoneHash
         *   - 0x1a0:  salt
         *   - 0x1c0:  conduit
         *   - 0x1e0:  _counters[orderParameters.offerer] (from storage)
         */
        uint256 constant BasicOrder_order_typeHash_ptr = 0x80;
        uint256 constant BasicOrder_order_offerer_ptr = 0xa0;
        // uint256 constant BasicOrder_order_zone_ptr = 0xc0;
        uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0;
        uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100;
        uint256 constant BasicOrder_order_orderType_ptr = 0x120;
        uint256 constant BasicOrder_order_startTime_ptr = 0x140;
        // uint256 constant BasicOrder_order_endTime_ptr = 0x160;
        // uint256 constant BasicOrder_order_zoneHash_ptr = 0x180;
        // uint256 constant BasicOrder_order_salt_ptr = 0x1a0;
        // uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0;
        uint256 constant BasicOrder_order_counter_ptr = 0x1e0;
        uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240;
        uint256 constant BasicOrder_signature_ptr = 0x260;
        uint256 constant BasicOrder_startTimeThroughZoneHash_size = 0x60;
        uint256 constant ContractOrder_orderHash_offerer_shift = 0x60;
        uint256 constant Counter_blockhash_shift = 0x80;
        // Signature-related
        bytes32 constant EIP2098_allButHighestBitMask =
            (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        bytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet =
            (0x0000000000000000000000000000000000000000000000000000000101000000);
        uint256 constant ECDSA_MaxLength = 65;
        uint256 constant ECDSA_signature_s_offset = 0x40;
        uint256 constant ECDSA_signature_v_offset = 0x60;
        bytes32 constant EIP1271_isValidSignature_selector =
            (0x1626ba7e00000000000000000000000000000000000000000000000000000000);
        uint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40;
        uint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44;
        uint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64;
        uint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40;
        uint256 constant EIP_712_PREFIX =
            (0x1901000000000000000000000000000000000000000000000000000000000000);
        uint256 constant ExtraGasBuffer = 0x20;
        uint256 constant CostPerWord = 0x3;
        uint256 constant MemoryExpansionCoefficientShift = 0x9;
        uint256 constant Create2AddressDerivation_ptr = 0x0b;
        uint256 constant Create2AddressDerivation_length = 0x55;
        uint256 constant MaskOverByteTwelve =
            (0x0000000000000000000000ff0000000000000000000000000000000000000000);
        uint256 constant MaskOverLastTwentyBytes =
            (0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff);
        uint256 constant AddressDirtyUpperBitThreshold =
            (0x0000000000000000000000010000000000000000000000000000000000000000);
        uint256 constant MaskOverFirstFourBytes =
            (0xffffffff00000000000000000000000000000000000000000000000000000000);
        uint256 constant Conduit_execute_signature =
            (0x4ce34aa200000000000000000000000000000000000000000000000000000000);
        uint256 constant MaxUint8 = 0xff;
        uint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff;
        uint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20;
        uint256 constant Conduit_execute_ConduitTransfer_length = 0x01;
        uint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04;
        uint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24;
        uint256 constant Conduit_execute_transferItemType_ptr = 0x44;
        uint256 constant Conduit_execute_transferToken_ptr = 0x64;
        uint256 constant Conduit_execute_transferFrom_ptr = 0x84;
        uint256 constant Conduit_execute_transferTo_ptr = 0xa4;
        uint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4;
        uint256 constant Conduit_execute_transferAmount_ptr = 0xe4;
        uint256 constant OneConduitExecute_size = 0x104;
        // Sentinel value to indicate that the conduit accumulator is not armed.
        uint256 constant AccumulatorDisarmed = 0x20;
        uint256 constant AccumulatorArmed = 0x40;
        uint256 constant Accumulator_conduitKey_ptr = 0x20;
        uint256 constant Accumulator_selector_ptr = 0x40;
        uint256 constant Accumulator_array_offset_ptr = 0x44;
        uint256 constant Accumulator_array_length_ptr = 0x64;
        uint256 constant Accumulator_itemSizeOffsetDifference = 0x3c;
        uint256 constant Accumulator_array_offset = 0x20;
        uint256 constant Conduit_transferItem_size = 0xc0;
        uint256 constant Conduit_transferItem_token_ptr = 0x20;
        uint256 constant Conduit_transferItem_from_ptr = 0x40;
        uint256 constant Conduit_transferItem_to_ptr = 0x60;
        uint256 constant Conduit_transferItem_identifier_ptr = 0x80;
        uint256 constant Conduit_transferItem_amount_ptr = 0xa0;
        uint256 constant Ecrecover_precompile = 0x1;
        uint256 constant Ecrecover_args_size = 0x80;
        uint256 constant Signature_lower_v = 27;
        // Bitmask that only gives a non-zero value if masked with a non-match selector.
        uint256 constant NonMatchSelector_MagicMask =
            (0x4000000000000000000000000000000000000000000000000000000000);
        // First bit indicates that a NATIVE offer items has been used and the 231st bit
        // indicates that a non match selector has been called.
        uint256 constant NonMatchSelector_InvalidErrorValue =
            (0x4000000000000000000000000000000000000000000000000000000001);
        /**
         * @dev Selector and offsets for generateOrder
         *
         * function generateOrder(
         *   address fulfiller,
         *   SpentItem[] calldata minimumReceived,
         *   SpentItem[] calldata maximumSpent,
         *   bytes calldata context
         * )
         */
        uint256 constant generateOrder_selector = 0x98919765;
        uint256 constant generateOrder_selector_offset = 0x1c;
        uint256 constant generateOrder_head_offset = 0x04;
        uint256 constant generateOrder_minimumReceived_head_offset = 0x20;
        uint256 constant generateOrder_maximumSpent_head_offset = 0x40;
        uint256 constant generateOrder_context_head_offset = 0x60;
        uint256 constant generateOrder_base_tail_offset = 0x80;
        uint256 constant generateOrder_maximum_returned_array_length = 0xffff;
        uint256 constant ratifyOrder_selector = 0xf4dd92ce;
        uint256 constant ratifyOrder_selector_offset = 0x1c;
        uint256 constant ratifyOrder_head_offset = 0x04;
        // uint256 constant ratifyOrder_offer_head_offset = 0x00;
        uint256 constant ratifyOrder_consideration_head_offset = 0x20;
        uint256 constant ratifyOrder_context_head_offset = 0x40;
        uint256 constant ratifyOrder_orderHashes_head_offset = 0x60;
        uint256 constant ratifyOrder_contractNonce_offset = 0x80;
        uint256 constant ratifyOrder_base_tail_offset = 0xa0;
        uint256 constant validateOrder_selector = 0x17b1f942;
        uint256 constant validateOrder_selector_offset = 0x1c;
        uint256 constant validateOrder_head_offset = 0x04;
        uint256 constant validateOrder_zoneParameters_offset = 0x20;
        uint256 constant authorizeOrder_selector = 0x01e4d72a;
        uint256 constant authorizeOrder_selector_offset = 0x1c;
        uint256 constant authorizeOrder_head_offset = 0x04;
        uint256 constant authorizeOrder_zoneParameters_offset = 0x20;
        // uint256 constant ZoneParameters_orderHash_offset = 0x00;
        uint256 constant ZoneParameters_fulfiller_offset = 0x20;
        uint256 constant ZoneParameters_offerer_offset = 0x40;
        uint256 constant ZoneParameters_offer_head_offset = 0x60;
        uint256 constant ZoneParameters_consideration_head_offset = 0x80;
        uint256 constant ZoneParameters_extraData_head_offset = 0xa0;
        uint256 constant ZoneParameters_orderHashes_head_offset = 0xc0;
        uint256 constant ZoneParameters_startTime_offset = 0xe0;
        uint256 constant ZoneParameters_endTime_offset = 0x100;
        uint256 constant ZoneParameters_zoneHash_offset = 0x120;
        uint256 constant ZoneParameters_base_tail_offset = 0x140;
        uint256 constant ZoneParameters_selectorAndPointer_length = 0x24;
        uint256 constant ZoneParameters_basicOrderFixedElements_length = 0x44;
        // ConsiderationDecoder Constants
        uint256 constant OrderParameters_head_size = 0x0160;
        uint256 constant OrderParameters_totalOriginalConsiderationItems_offset = (
            0x0140
        );
        uint256 constant AdvancedOrderPlusOrderParameters_head_size = 0x0200;
        uint256 constant Order_signature_offset = 0x20;
        uint256 constant Order_head_size = 0x40;
        uint256 constant AdvancedOrder_fixed_segment_0 = 0x40;
        uint256 constant CriteriaResolver_head_size = 0xa0;
        uint256 constant CriteriaResolver_fixed_segment_0 = 0x80;
        uint256 constant CriteriaResolver_criteriaProof_offset = 0x80;
        uint256 constant FulfillmentComponent_mem_tail_size = 0x40;
        uint256 constant FulfillmentComponent_mem_tail_size_shift = 0x6;
        uint256 constant Fulfillment_head_size = 0x40;
        uint256 constant Fulfillment_considerationComponents_offset = 0x20;
        uint256 constant OrderComponents_OrderParameters_common_head_size = 0x0140;
        // 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.24;
        import {
            ItemType,
            OrderType
        } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            ConsiderationItem,
            CriteriaResolver,
            OfferItem,
            OrderParameters,
            ReceivedItem,
            SpentItem
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol";
        import { CriteriaResolution } from "./CriteriaResolution.sol";
        import { AmountDeriver } from "./AmountDeriver.sol";
        import {
            _revertInsufficientNativeTokensSupplied,
            _revertInvalidNativeOfferItem
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            AccumulatorDisarmed,
            ConsiderationItem_recipient_offset,
            ReceivedItem_amount_offset,
            ReceivedItem_recipient_offset
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        /**
         * @title OrderFulfiller
         * @author 0age
         * @notice OrderFulfiller contains logic related to order fulfillment where a
         *         single order is being fulfilled and where basic order fulfillment is
         *         not available as an option.
         */
        contract OrderFulfiller is
            BasicOrderFulfiller,
            CriteriaResolution,
            AmountDeriver
        {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(
                address conduitController
            ) BasicOrderFulfiller(conduitController) {}
            /**
             * @dev Internal function to validate an order and update its status, adjust
             *      prices based on current time, apply criteria resolvers, determine
             *      what portion to fill, and transfer relevant tokens.
             *
             * @param advancedOrder       The order to fulfill as well as the fraction
             *                            to fill. Note that all offer and consideration
             *                            components must divide with no remainder for
             *                            the partial fill to be valid.
             * @param criteriaResolvers   An array where each element contains a
             *                            reference to a specific offer or
             *                            consideration, a token identifier, and a proof
             *                            that the supplied token identifier is
             *                            contained in the order's merkle root. Note
             *                            that a criteria of zero indicates that any
             *                            (transferable) token identifier is valid and
             *                            that no proof needs to be supplied.
             * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
             *                            any, to source the fulfiller's token approvals
             *                            from. The zero hash signifies that no conduit
             *                            should be used, with direct approvals set on
             *                            Consideration.
             * @param recipient           The intended recipient for all received items.
             *
             * @return A boolean indicating whether the order has been fulfilled.
             */
            function _validateAndFulfillAdvancedOrder(
                AdvancedOrder memory advancedOrder,
                CriteriaResolver[] memory criteriaResolvers,
                bytes32 fulfillerConduitKey,
                address recipient
            ) internal returns (bool) {
                // Retrieve the order parameters and order type.
                OrderParameters memory orderParameters = advancedOrder.parameters;
                OrderType orderType = orderParameters.orderType;
                // Ensure this function cannot be triggered during a reentrant call.
                _setReentrancyGuard(
                    // Native tokens accepted during execution for contract order types.
                    orderType == OrderType.CONTRACT
                );
                // Validate order, update status, and determine fraction to fill.
                (
                    bytes32 orderHash,
                    uint256 fillNumerator,
                    uint256 fillDenominator
                ) = _validateOrder(advancedOrder, _runTimeConstantTrue());
                // Create an array with length 1 containing the order.
                AdvancedOrder[] memory advancedOrders = new AdvancedOrder[](1);
                // Populate the order as the first and only element of the new array.
                advancedOrders[0] = advancedOrder;
                // Apply criteria resolvers using generated orders and details arrays.
                _applyCriteriaResolvers(advancedOrders, criteriaResolvers);
                // Derive each item transfer with the appropriate fractional amount.
                _applyFractions(
                    orderParameters,
                    fillNumerator,
                    fillDenominator,
                    recipient
                );
                // Declare an empty length-1 array to hold the order hash, but do not
                // write to it until after the order has been authorized or generated.
                bytes32[] memory orderHashes = new bytes32[](1);
                // Declare a boolean that cannot be optimized out by the compiler
                // outside of the if-else statement so it can be used in either.
                bool _true = _runTimeConstantTrue();
                if (orderType != OrderType.CONTRACT) {
                    _assertRestrictedAdvancedOrderAuthorization(
                        advancedOrder,
                        orderHashes,
                        orderHash,
                        0
                    );
                    _updateStatus(orderHash, fillNumerator, fillDenominator, _true);
                } else {
                    // Return the generated order based on the order params and the
                    // provided extra data.
                    orderHash = _getGeneratedOrder(
                        orderParameters,
                        advancedOrder.extraData,
                        _true
                    );
                }
                _transferEach(orderParameters, fulfillerConduitKey, recipient);
                // Write the order hash to the orderHashes array.
                orderHashes[0] = orderHash;
                // Ensure restricted orders have a valid submitter or pass a zone check.
                _assertRestrictedAdvancedOrderValidity(
                    advancedOrder,
                    orderHashes,
                    orderHash
                );
                // Emit an event signifying that the order has been fulfilled.
                _emitOrderFulfilledEvent(
                    orderHash,
                    orderParameters.offerer,
                    orderParameters.zone,
                    recipient,
                    orderParameters.offer,
                    orderParameters.consideration
                );
                // Clear the reentrancy guard.
                _clearReentrancyGuard();
                return true;
            }
            /**
             * @dev Internal function to derive the amount to transfer for each item in
             *      a given order based on the fraction to fill and the current time.
             *
             * @param orderParameters     The parameters for the fulfilled order.
             * @param numerator           A value indicating the portion of the order
             *                            that should be filled.
             * @param denominator         A value indicating the total order size.
             * @param recipient           The intended recipient for all received items.
             */
            function _applyFractions(
                OrderParameters memory orderParameters,
                uint256 numerator,
                uint256 denominator,
                address recipient
            ) internal view {
                // Read start time & end time from order parameters and place on stack.
                uint256 startTime = orderParameters.startTime;
                uint256 endTime = orderParameters.endTime;
                // As of solidity 0.6.0, inline assembly cannot directly access function
                // definitions, but can still access locally scoped function variables.
                // This means that a local variable to reference the internal function
                // definition (using the same type), along with a local variable with
                // the desired type, must first be created. Then, the original function
                // pointer can be recast to the desired type.
                /**
                 * Repurpose existing OfferItem memory regions on the offer array for
                 * the order by overriding the _transfer function pointer to accept a
                 * modified OfferItem argument in place of the usual ReceivedItem:
                 *
                 *   ========= OfferItem ==========   ====== ReceivedItem ======
                 *   ItemType itemType; ------------> ItemType itemType;
                 *   address token; ----------------> address token;
                 *   uint256 identifierOrCriteria; -> uint256 identifier;
                 *   uint256 startAmount; ----------> uint256 amount;
                 *   uint256 endAmount; ------------> address recipient;
                 */
                // Declare a nested scope to minimize stack depth.
                unchecked {
                    // Read offer array length from memory and place on stack.
                    uint256 totalOfferItems = orderParameters.offer.length;
                    // Create a variable to indicate whether the order has any
                    // native offer items
                    uint256 anyNativeItems;
                    // Iterate over each offer on the order.
                    // Skip overflow check as for loop is indexed starting at zero.
                    for (uint256 i = 0; i < totalOfferItems; ++i) {
                        // Retrieve the offer item.
                        OfferItem memory offerItem = orderParameters.offer[i];
                        // Offer items for the native token can not be received outside
                        // of a match order function except as part of a contract order.
                        {
                            ItemType itemType = offerItem.itemType;
                            assembly {
                                anyNativeItems := or(anyNativeItems, iszero(itemType))
                            }
                        }
                        // Declare an additional nested scope to minimize stack depth.
                        {
                            // Apply fill fraction to get offer item amount to transfer.
                            uint256 amount = _applyFraction(
                                offerItem.startAmount,
                                offerItem.endAmount,
                                numerator,
                                denominator,
                                startTime,
                                endTime,
                                _runTimeConstantFalse()
                            );
                            // Utilize assembly to set overloaded offerItem arguments.
                            assembly {
                                // Write new fractional amount to startAmount as amount.
                                mstore(
                                    add(offerItem, ReceivedItem_amount_offset),
                                    amount
                                )
                                // Write recipient to endAmount.
                                mstore(
                                    add(offerItem, ReceivedItem_recipient_offset),
                                    recipient
                                )
                            }
                        }
                    }
                    // If a non-contract order has native offer items, throw with an
                    // `InvalidNativeOfferItem` custom error.
                    {
                        OrderType orderType = orderParameters.orderType;
                        uint256 invalidNativeOfferItem;
                        assembly {
                            invalidNativeOfferItem := and(
                                // Note that this check requires that there are no
                                // order types beyond the current set (0-4). It will
                                // need to be modified when adding more order types.
                                lt(orderType, 4),
                                anyNativeItems
                            )
                        }
                        if (invalidNativeOfferItem != 0) {
                            _revertInvalidNativeOfferItem();
                        }
                    }
                }
                /**
                 * Repurpose existing ConsiderationItem memory regions on the
                 * consideration array for the order by overriding the _transfer
                 * function pointer to accept a modified ConsiderationItem argument in
                 * place of the usual ReceivedItem:
                 *
                 *   ====== ConsiderationItem =====   ====== ReceivedItem ======
                 *   ItemType itemType; ------------> ItemType itemType;
                 *   address token; ----------------> address token;
                 *   uint256 identifierOrCriteria;--> uint256 identifier;
                 *   uint256 startAmount; ----------> uint256 amount;
                 *   uint256 endAmount;        /----> address recipient;
                 *   address recipient; ------/
                 */
                // Declare a nested scope to minimize stack depth.
                unchecked {
                    // Read consideration array length from memory and place on stack.
                    uint256 totalConsiderationItems = orderParameters
                        .consideration
                        .length;
                    // Iterate over each consideration item on the order.
                    // Skip overflow check as for loop is indexed starting at zero.
                    for (uint256 i = 0; i < totalConsiderationItems; ++i) {
                        // Retrieve the consideration item.
                        ConsiderationItem memory considerationItem = (
                            orderParameters.consideration[i]
                        );
                        // Apply fraction & derive considerationItem amount to transfer.
                        uint256 amount = _applyFraction(
                            considerationItem.startAmount,
                            considerationItem.endAmount,
                            numerator,
                            denominator,
                            startTime,
                            endTime,
                            _runTimeConstantTrue()
                        );
                        // Use assembly to set overloaded considerationItem arguments.
                        assembly {
                            // Write derived fractional amount to startAmount as amount.
                            mstore(
                                add(considerationItem, ReceivedItem_amount_offset),
                                amount
                            )
                            // Write original recipient to endAmount as recipient.
                            mstore(
                                add(considerationItem, ReceivedItem_recipient_offset),
                                mload(
                                    add(
                                        considerationItem,
                                        ConsiderationItem_recipient_offset
                                    )
                                )
                            )
                        }
                    }
                }
            }
            /**
             * @dev Internal function to transfer each item contained in a given single
             *      order fulfillment.
             *
             * @param orderParameters     The parameters for the fulfilled order.
             * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
             *                            any, to source the fulfiller's token approvals
             *                            from. The zero hash signifies that no conduit
             *                            should be used, with direct approvals set on
             *                            Consideration.
             * @param recipient           The intended recipient for all received items.
             */
            function _transferEach(
                OrderParameters memory orderParameters,
                bytes32 fulfillerConduitKey,
                address recipient
            ) internal {
                // Initialize an accumulator array. From this point forward, no new
                // memory regions can be safely allocated until the accumulator is no
                // longer being utilized, as the accumulator operates in an open-ended
                // fashion from this memory pointer; existing memory may still be
                // accessed and modified, however.
                bytes memory accumulator = new bytes(AccumulatorDisarmed);
                // As of solidity 0.6.0, inline assembly cannot directly access function
                // definitions, but can still access locally scoped function variables.
                // This means that a local variable to reference the internal function
                // definition (using the same type), along with a local variable with
                // the desired type, must first be created. Then, the original function
                // pointer can be recast to the desired type.
                /**
                 * Repurpose existing OfferItem memory regions on the offer array for
                 * the order by overriding the _transfer function pointer to accept a
                 * modified OfferItem argument in place of the usual ReceivedItem:
                 *
                 *   ========= OfferItem ==========   ====== ReceivedItem ======
                 *   ItemType itemType; ------------> ItemType itemType;
                 *   address token; ----------------> address token;
                 *   uint256 identifierOrCriteria; -> uint256 identifier;
                 *   uint256 startAmount; ----------> uint256 amount;
                 *   uint256 endAmount; ------------> address recipient;
                 */
                // Declare a nested scope to minimize stack depth.
                unchecked {
                    // Read offer array length from memory and place on stack.
                    uint256 totalOfferItems = orderParameters.offer.length;
                    // Iterate over each offer on the order.
                    // Skip overflow check as for loop is indexed starting at zero.
                    for (uint256 i = 0; i < totalOfferItems; ++i) {
                        // Retrieve the offer item.
                        OfferItem memory offerItem = orderParameters.offer[i];
                        // Utilize assembly to set overloaded offerItem arguments.
                        assembly {
                            // Write recipient to endAmount.
                            mstore(
                                add(offerItem, ReceivedItem_recipient_offset),
                                recipient
                            )
                        }
                        // Transfer the item from the offerer to the recipient.
                        _toOfferItemInput(_transfer)(
                            offerItem,
                            orderParameters.offerer,
                            orderParameters.conduitKey,
                            accumulator
                        );
                    }
                }
                // Declare a variable for the available native token balance.
                uint256 nativeTokenBalance;
                /**
                 * Repurpose existing ConsiderationItem memory regions on the
                 * consideration array for the order by overriding the _transfer
                 * function pointer to accept a modified ConsiderationItem argument in
                 * place of the usual ReceivedItem:
                 *
                 *   ====== ConsiderationItem =====   ====== ReceivedItem ======
                 *   ItemType itemType; ------------> ItemType itemType;
                 *   address token; ----------------> address token;
                 *   uint256 identifierOrCriteria;--> uint256 identifier;
                 *   uint256 startAmount; ----------> uint256 amount;
                 *   uint256 endAmount;        /----> address recipient;
                 *   address recipient; ------/
                 */
                // Declare a nested scope to minimize stack depth.
                unchecked {
                    // Read consideration array length from memory and place on stack.
                    uint256 totalConsiderationItems = orderParameters
                        .consideration
                        .length;
                    // Iterate over each consideration item on the order.
                    // Skip overflow check as for loop is indexed starting at zero.
                    for (uint256 i = 0; i < totalConsiderationItems; ++i) {
                        // Retrieve the consideration item.
                        ConsiderationItem memory considerationItem = (
                            orderParameters.consideration[i]
                        );
                        if (considerationItem.itemType == ItemType.NATIVE) {
                            // Get the current available balance of native tokens.
                            assembly {
                                nativeTokenBalance := selfbalance()
                            }
                            // Ensure that sufficient native tokens are still available.
                            if (considerationItem.startAmount > nativeTokenBalance) {
                                _revertInsufficientNativeTokensSupplied();
                            }
                        }
                        // Transfer item from caller to recipient specified by the item.
                        _toConsiderationItemInput(_transfer)(
                            considerationItem,
                            msg.sender,
                            fulfillerConduitKey,
                            accumulator
                        );
                    }
                }
                // Trigger any remaining accumulated transfers via call to the conduit.
                _triggerIfArmed(accumulator);
                // Determine whether any native token balance remains.
                assembly {
                    nativeTokenBalance := selfbalance()
                }
                // Return any remaining native token balance to the caller.
                if (nativeTokenBalance != 0) {
                    _transferNativeTokens(payable(msg.sender), nativeTokenBalance);
                }
            }
            /**
             * @dev Internal function to emit an OrderFulfilled event. OfferItems are
             *      translated into SpentItems and ConsiderationItems are translated
             *      into ReceivedItems.
             *
             * @param orderHash     The order hash.
             * @param offerer       The offerer for the order.
             * @param zone          The zone for the order.
             * @param recipient     The recipient of the order, or the null address if
             *                      the order was fulfilled via order matching.
             * @param offer         The offer items for the order.
             * @param consideration The consideration items for the order.
             */
            function _emitOrderFulfilledEvent(
                bytes32 orderHash,
                address offerer,
                address zone,
                address recipient,
                OfferItem[] memory offer,
                ConsiderationItem[] memory consideration
            ) internal {
                // Cast already-modified offer memory region as spent items.
                SpentItem[] memory spentItems;
                assembly {
                    spentItems := offer
                }
                // Cast already-modified consideration memory region as received items.
                ReceivedItem[] memory receivedItems;
                assembly {
                    receivedItems := consideration
                }
                // Emit an event signifying that the order has been fulfilled.
                emit OrderFulfilled(
                    orderHash,
                    offerer,
                    zone,
                    recipient,
                    spentItems,
                    receivedItems
                );
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import { ItemType, Side } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            Execution,
            FulfillmentComponent,
            ReceivedItem
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            _revertMissingFulfillmentComponentOnAggregation
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            FulfillmentApplicationErrors
        } from "seaport-types/src/interfaces/FulfillmentApplicationErrors.sol";
        import {
            AdvancedOrder_numerator_offset,
            Common_amount_offset,
            Common_identifier_offset,
            Common_token_offset,
            Execution_conduit_offset,
            Execution_offerer_offset,
            Fulfillment_itemIndex_offset,
            OneWord,
            OneWordShift,
            OrderParameters_conduit_offset,
            OrderParameters_consideration_head_offset,
            OrderParameters_offer_head_offset,
            ReceivedItem_CommonParams_size,
            ReceivedItem_recipient_offset,
            ReceivedItem_size
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            InvalidFulfillmentComponentData_error_length,
            InvalidFulfillmentComponentData_error_selector,
            MismatchedOfferAndConsiderationComponents_error_idx_ptr,
            MismatchedOfferAndConsiderationComponents_error_length,
            MismatchedOfferAndConsiderationComponents_error_selector,
            MissingItemAmount_error_length,
            MissingItemAmount_error_selector,
            OfferAndConsiderationRequiredOnFulfillment_error_length,
            OfferAndConsiderationRequiredOnFulfillment_error_selector,
            Panic_arithmetic,
            Panic_error_code_ptr,
            Panic_error_length,
            Panic_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title FulfillmentApplier
         * @author 0age
         * @notice FulfillmentApplier contains logic related to applying fulfillments,
         *         both as part of order matching (where offer items are matched to
         *         consideration items) as well as fulfilling available orders (where
         *         order items and consideration items are independently aggregated).
         */
        contract FulfillmentApplier is FulfillmentApplicationErrors {
            /**
             * @dev Internal pure function to match offer items to consideration items
             *      on a group of orders via a supplied fulfillment.
             *
             * @param advancedOrders          The orders to match.
             * @param offerComponents         An array designating offer components to
             *                                match to consideration components.
             * @param considerationComponents An array designating consideration
             *                                components to match to offer components.
             *                                Note that each consideration amount must
             *                                be zero in order for the match operation
             *                                to be valid.
             * @param fulfillmentIndex        The index of the fulfillment being
             *                                applied.
             *
             * @return execution The transfer performed as a result of the fulfillment.
             */
            function _applyFulfillment(
                AdvancedOrder[] memory advancedOrders,
                FulfillmentComponent[] memory offerComponents,
                FulfillmentComponent[] memory considerationComponents,
                uint256 fulfillmentIndex
            ) internal pure returns (Execution memory execution) {
                // Ensure 1+ of both offer and consideration components are supplied.
                assembly {
                    if or(
                        iszero(mload(offerComponents)),
                        iszero(mload(considerationComponents))
                    ) {
                        // Store left-padded selector with push4 (reduces bytecode),
                        // mem[28:32] = selector
                        mstore(
                            0,
                            OfferAndConsiderationRequiredOnFulfillment_error_selector
                        )
                        // revert(abi.encodeWithSignature(
                        //     "OfferAndConsiderationRequiredOnFulfillment()"
                        // ))
                        revert(
                            Error_selector_offset,
                            OfferAndConsiderationRequiredOnFulfillment_error_length
                        )
                    }
                }
                // Declare a new Execution struct.
                Execution memory considerationExecution;
                // Validate & aggregate consideration items to new Execution object.
                _aggregateValidFulfillmentConsiderationItems(
                    advancedOrders,
                    considerationComponents,
                    considerationExecution,
                    address(0),
                    bytes32(0)
                );
                // Retrieve the consideration item from the execution struct.
                ReceivedItem memory considerationItem = considerationExecution.item;
                // Skip aggregating offer items if no consideration items are available.
                if (considerationItem.amount == 0) {
                    return considerationExecution;
                }
                // Validate & aggregate offer items to Execution object.
                _aggregateValidFulfillmentOfferItems(
                    advancedOrders,
                    offerComponents,
                    execution,
                    considerationItem.recipient
                );
                ReceivedItem memory executionItem = execution.item;
                // Ensure offer & consideration item types, tokens, & identifiers match.
                // (a != b || c != d || e != f) == (((a ^ b) | (c ^ d) | (e ^ f)) != 0),
                // but the second expression requires less gas to evaluate.
                assembly {
                    if or(
                        or(
                            xor(
                                mload(executionItem), // no offset for item type
                                mload(considerationItem) // no offset for item type
                            ),
                            xor(
                                mload(add(executionItem, Common_token_offset)),
                                mload(add(considerationItem, Common_token_offset))
                            )
                        ),
                        xor(
                            mload(add(executionItem, Common_identifier_offset)),
                            mload(add(considerationItem, Common_identifier_offset))
                        )
                    ) {
                        // Store left-padded selector with push4 (reduces bytecode),
                        // mem[28:32] = selector
                        mstore(
                            0,
                            MismatchedOfferAndConsiderationComponents_error_selector
                        )
                        // Store fulfillment index argument.
                        mstore(
                            MismatchedOfferAndConsiderationComponents_error_idx_ptr,
                            fulfillmentIndex
                        )
                        // Revert: `MismatchedOfferAndConsiderationComponents(uint256)`
                        revert(
                            Error_selector_offset,
                            MismatchedOfferAndConsiderationComponents_error_length
                        )
                    }
                }
                // If total consideration amount exceeds the offer amount...
                if (considerationItem.amount > executionItem.amount) {
                    // Retrieve the first consideration component from the fulfillment.
                    FulfillmentComponent memory targetComponent = (
                        considerationComponents[0]
                    );
                    // Skip underflow check as the conditional being true implies that
                    // considerationItem.amount > execution.item.amount.
                    unchecked {
                        // Add excess consideration item amount to original order array.
                        advancedOrders[targetComponent.orderIndex]
                            .parameters
                            .consideration[targetComponent.itemIndex]
                            .startAmount = (considerationItem.amount -
                            executionItem.amount);
                    }
                } else {
                    // Retrieve the first offer component from the fulfillment.
                    FulfillmentComponent memory targetComponent = offerComponents[0];
                    // Skip underflow check as the conditional being false implies that
                    // execution.item.amount >= considerationItem.amount.
                    unchecked {
                        // Add excess offer item amount to the original array of orders.
                        advancedOrders[targetComponent.orderIndex]
                            .parameters
                            .offer[targetComponent.itemIndex]
                            .startAmount = (executionItem.amount -
                            considerationItem.amount);
                    }
                    // Reduce total offer amount to equal the consideration amount.
                    executionItem.amount = considerationItem.amount;
                }
                // Return the final execution that will be triggered for relevant items.
                return execution; // Execution(executionItem, offerer, conduitKey);
            }
            /**
             * @dev Internal view function to aggregate offer or consideration items
             *      from a group of orders into a single execution via a supplied array
             *      of fulfillment components. Items that are not available to aggregate
             *      will not be included in the aggregated execution.
             *
             * @param advancedOrders        The orders to aggregate.
             * @param side                  The side (i.e. offer or consideration).
             * @param fulfillmentComponents An array designating item components to
             *                              aggregate if part of an available order.
             * @param fulfillerConduitKey   A bytes32 value indicating what conduit, if
             *                              any, to source the fulfiller's token
             *                              approvals from. The zero hash signifies that
             *                              no conduit should be used, with approvals
             *                              set directly on this contract.
             * @param recipient             The intended recipient for all received
             *                              items.
             *
             * @return execution The transfer performed as a result of the fulfillment.
             */
            function _aggregateAvailable(
                AdvancedOrder[] memory advancedOrders,
                Side side,
                FulfillmentComponent[] memory fulfillmentComponents,
                bytes32 fulfillerConduitKey,
                address recipient
            ) internal view returns (Execution memory execution) {
                // Skip overflow / underflow checks; conditions checked or unreachable.
                unchecked {
                    // Retrieve fulfillment components array length and place on stack.
                    // Ensure at least one fulfillment component has been supplied.
                    if (fulfillmentComponents.length == 0) {
                        _revertMissingFulfillmentComponentOnAggregation(side);
                    }
                    // If the fulfillment components are offer components...
                    if (side == Side.OFFER) {
                        // Return execution for aggregated items provided by offerer.
                        _aggregateValidFulfillmentOfferItems(
                            advancedOrders,
                            fulfillmentComponents,
                            execution,
                            payable(recipient)
                        );
                    } else {
                        // Otherwise, fulfillment components are consideration
                        // components. Return execution for aggregated items provided by
                        // the fulfiller.
                        _aggregateValidFulfillmentConsiderationItems(
                            advancedOrders,
                            fulfillmentComponents,
                            execution,
                            msg.sender,
                            fulfillerConduitKey
                        );
                    }
                }
            }
            /**
             * @dev Internal pure function to aggregate a group of offer items using
             *      supplied directives on which component items are candidates for
             *      aggregation, skipping items on orders that are not available.
             *
             * @param advancedOrders  The orders to aggregate offer items from.
             * @param offerComponents An array of FulfillmentComponent structs
             *                        indicating the order index and item index of each
             *                        candidate offer item for aggregation.
             * @param execution       The execution to apply the aggregation to.
             * @param recipient       The intended recipient for the received item.
             */
            function _aggregateValidFulfillmentOfferItems(
                AdvancedOrder[] memory advancedOrders,
                FulfillmentComponent[] memory offerComponents,
                Execution memory execution,
                address payable recipient
            ) internal pure {
                assembly {
                    // Declare a variable for the final aggregated item amount.
                    let amount
                    // Declare a variable to track errors encountered with amount.
                    let errorBuffer
                    // Declare a variable for the hash of itemType, token, & identifier.
                    let dataHash
                    // Iterate over each offer component.
                    for {
                        // Create variable to track position in offerComponents head.
                        let fulfillmentHeadPtr := offerComponents
                        // Get position of the last element in head of array.
                        let endPtr := add(
                            offerComponents,
                            shl(OneWordShift, mload(offerComponents))
                        )
                    } lt(fulfillmentHeadPtr, endPtr) {
                    } {
                        // Increment position in considerationComponents head.
                        fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                        // Ensure that the order index is not out of range.
                        if iszero(
                            lt(mload(mload(fulfillmentHeadPtr)), mload(advancedOrders))
                        ) {
                            throwInvalidFulfillmentComponentData()
                        }
                        // Read advancedOrders[orderIndex] pointer from its array head.
                        let orderPtr := mload(
                            // Calculate head position of advancedOrders[orderIndex]
                            add(
                                add(advancedOrders, OneWord),
                                shl(OneWordShift, mload(mload(fulfillmentHeadPtr)))
                            )
                        )
                        // Read the pointer to OrderParameters from the AdvancedOrder.
                        let paramsPtr := mload(orderPtr)
                        // Retrieve item index using an offset of fulfillment pointer.
                        let itemIndex := mload(
                            add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                        )
                        let offerItemPtr
                        {
                            // Load the offer array pointer.
                            let offerArrPtr := mload(
                                add(paramsPtr, OrderParameters_offer_head_offset)
                            )
                            // If the offer item index is out of range or the numerator
                            // is zero, skip this item.
                            if or(
                                iszero(lt(itemIndex, mload(offerArrPtr))),
                                iszero(
                                    mload(add(orderPtr, AdvancedOrder_numerator_offset))
                                )
                            ) {
                                continue
                            }
                            // Retrieve offer item pointer using the item index.
                            offerItemPtr := mload(
                                add(
                                    // Get pointer to beginning of receivedItem.
                                    add(offerArrPtr, OneWord),
                                    // Calculate offset to pointer for the order.
                                    shl(OneWordShift, itemIndex)
                                )
                            )
                        }
                        // Declare a separate scope for the amount update.
                        {
                            // Retrieve amount pointer using consideration item pointer.
                            let amountPtr := add(offerItemPtr, Common_amount_offset)
                            // Add offer item amount to execution amount.
                            let newAmount := add(amount, mload(amountPtr))
                            // Update error buffer:
                            // 1 = zero amount, 2 = overflow, 3 = both.
                            errorBuffer := or(
                                errorBuffer,
                                or(
                                    shl(1, lt(newAmount, amount)),
                                    iszero(mload(amountPtr))
                                )
                            )
                            // Update the amount to the new, summed amount.
                            amount := newAmount
                            // Zero out amount on original item to indicate it is spent.
                            mstore(amountPtr, 0)
                        }
                        // Retrieve ReceivedItem pointer from Execution.
                        let receivedItem := mload(execution)
                        // Check if this is the first valid fulfillment item.
                        switch iszero(dataHash)
                        case 1 {
                            // On first valid item, populate the received item in memory
                            // for later comparison.
                            // Set the item type on the received item.
                            mstore(receivedItem, mload(offerItemPtr))
                            // Set the token on the received item.
                            mstore(
                                add(receivedItem, Common_token_offset),
                                mload(add(offerItemPtr, Common_token_offset))
                            )
                            // Set the identifier on the received item.
                            mstore(
                                add(receivedItem, Common_identifier_offset),
                                mload(add(offerItemPtr, Common_identifier_offset))
                            )
                            // Set the recipient on the received item.
                            mstore(
                                add(receivedItem, ReceivedItem_recipient_offset),
                                recipient
                            )
                            // Set offerer on returned execution using order pointer.
                            mstore(
                                add(execution, Execution_offerer_offset),
                                mload(paramsPtr)
                            )
                            // Set execution conduitKey via order pointer offset.
                            mstore(
                                add(execution, Execution_conduit_offset),
                                mload(add(paramsPtr, OrderParameters_conduit_offset))
                            )
                            // Calculate the hash of (itemType, token, identifier).
                            dataHash := keccak256(
                                receivedItem,
                                ReceivedItem_CommonParams_size
                            )
                            // If component index > 0, swap component pointer with
                            // pointer to first component so that any remainder after
                            // fulfillment can be added back to the first item.
                            let firstFulfillmentHeadPtr := add(offerComponents, OneWord)
                            if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) {
                                let fulfillmentPtr := mload(fulfillmentHeadPtr)
                                mstore(firstFulfillmentHeadPtr, fulfillmentPtr)
                            }
                        }
                        default {
                            // Compare every subsequent item to the first.
                            if or(
                                or(
                                    // The offerer must match on both items.
                                    xor(
                                        mload(paramsPtr),
                                        mload(add(execution, Execution_offerer_offset))
                                    ),
                                    // The conduit key must match on both items.
                                    xor(
                                        mload(
                                            add(
                                                paramsPtr,
                                                OrderParameters_conduit_offset
                                            )
                                        ),
                                        mload(add(execution, Execution_conduit_offset))
                                    )
                                ),
                                // The itemType, token, and identifier must match.
                                xor(
                                    dataHash,
                                    keccak256(
                                        offerItemPtr,
                                        ReceivedItem_CommonParams_size
                                    )
                                )
                            ) {
                                // Throw if any of the requirements are not met.
                                throwInvalidFulfillmentComponentData()
                            }
                        }
                    }
                    // Write final amount to execution.
                    mstore(add(mload(execution), Common_amount_offset), amount)
                    // Determine whether the error buffer contains a nonzero error code.
                    if errorBuffer {
                        // If errorBuffer is 1, an item had an amount of zero.
                        if eq(errorBuffer, 1) {
                            // Store left-padded selector with push4 (reduces bytecode)
                            // mem[28:32] = selector
                            mstore(0, MissingItemAmount_error_selector)
                            // revert(abi.encodeWithSignature("MissingItemAmount()"))
                            revert(
                                Error_selector_offset,
                                MissingItemAmount_error_length
                            )
                        }
                        // If errorBuffer is not 1 or 0, the sum overflowed.
                        // Panic!
                        throwOverflow()
                    }
                    // Declare function for reverts on invalid fulfillment data.
                    function throwInvalidFulfillmentComponentData() {
                        // Store left-padded selector (uses push4 and reduces code size)
                        mstore(0, InvalidFulfillmentComponentData_error_selector)
                        // revert(abi.encodeWithSignature(
                        //     "InvalidFulfillmentComponentData()"
                        // ))
                        revert(
                            Error_selector_offset,
                            InvalidFulfillmentComponentData_error_length
                        )
                    }
                    // Declare function for reverts due to arithmetic overflows.
                    function throwOverflow() {
                        // Store the Panic error signature.
                        mstore(0, Panic_error_selector)
                        // Store the arithmetic (0x11) panic code.
                        mstore(Panic_error_code_ptr, Panic_arithmetic)
                        // revert(abi.encodeWithSignature("Panic(uint256)", 0x11))
                        revert(Error_selector_offset, Panic_error_length)
                    }
                }
            }
            /**
             * @dev Internal pure function to aggregate a group of consideration items
             *      using supplied directives on which component items are candidates
             *      for aggregation, skipping items on orders that are not available.
             *      Note that this function depends on memory layout affected by an
             *      earlier call to _validateOrdersAndPrepareToFulfill. The memory for
             *      the consideration arrays needs to be updated before calling
             *      _aggregateValidFulfillmentConsiderationItems.
             *      _validateOrdersAndPrepareToFulfill is called in _matchAdvancedOrders
             *      and _fulfillAvailableAdvancedOrders in the current version.
             *
             * @param advancedOrders          The orders to aggregate consideration
             *                                items from.
             * @param considerationComponents An array of FulfillmentComponent structs
             *                                indicating the order index and item index
             *                                of each candidate consideration item for
             *                                aggregation.
             * @param execution               The execution to apply the aggregation to.
             * @param offerer                 The address of the offerer to set on the
             *                                execution.
             * @param conduitKey              A bytes32 value indicating the conduit key
             *                                to set on the execution.
             */
            function _aggregateValidFulfillmentConsiderationItems(
                AdvancedOrder[] memory advancedOrders,
                FulfillmentComponent[] memory considerationComponents,
                Execution memory execution,
                address offerer,
                bytes32 conduitKey
            ) internal pure {
                // Utilize assembly in order to efficiently aggregate the items.
                assembly {
                    // Declare a variable for the final aggregated item amount.
                    let amount
                    // Create variable to track errors encountered with amount.
                    let errorBuffer
                    // Declare variable for hash(itemType, token, identifier, recipient)
                    let dataHash
                    // Iterate over each consideration component.
                    for {
                        // Track position in considerationComponents head.
                        let fulfillmentHeadPtr := considerationComponents
                        // Get position of the last element in head of array.
                        let endPtr := add(
                            considerationComponents,
                            shl(OneWordShift, mload(considerationComponents))
                        )
                    } lt(fulfillmentHeadPtr, endPtr) {
                    } {
                        // Increment position in considerationComponents head.
                        fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                        // Retrieve the order index using the fulfillment pointer.
                        let orderIndex := mload(mload(fulfillmentHeadPtr))
                        // Ensure that the order index is not out of range.
                        if iszero(lt(orderIndex, mload(advancedOrders))) {
                            throwInvalidFulfillmentComponentData()
                        }
                        // Read advancedOrders[orderIndex] pointer from its array head.
                        let orderPtr := mload(
                            // Derive head position of advancedOrders[orderIndex].
                            add(
                                add(advancedOrders, OneWord),
                                shl(OneWordShift, orderIndex)
                            )
                        )
                        // Retrieve item index using an offset of fulfillment pointer.
                        let itemIndex := mload(
                            add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                        )
                        let considerationItemPtr
                        {
                            // Load consideration array pointer.
                            let considerationArrPtr := mload(
                                add(
                                    // Read OrderParameters pointer from the order.
                                    mload(orderPtr),
                                    OrderParameters_consideration_head_offset
                                )
                            )
                            // If the consideration item index is out of range or the
                            // numerator is zero, skip this item.
                            if or(
                                iszero(lt(itemIndex, mload(considerationArrPtr))),
                                iszero(
                                    mload(add(orderPtr, AdvancedOrder_numerator_offset))
                                )
                            ) {
                                continue
                            }
                            // Retrieve consideration item pointer using the item index.
                            considerationItemPtr := mload(
                                add(
                                    // Get pointer to beginning of receivedItem.
                                    add(considerationArrPtr, OneWord),
                                    // Calculate offset to pointer for the order.
                                    shl(OneWordShift, itemIndex)
                                )
                            )
                        }
                        // Declare a separate scope for the amount update.
                        {
                            // Retrieve amount pointer using consideration item pointer.
                            let amountPtr := add(
                                considerationItemPtr,
                                Common_amount_offset
                            )
                            // Add consideration item amount to execution amount.
                            let newAmount := add(amount, mload(amountPtr))
                            // Update error buffer:
                            // 1 = zero amount, 2 = overflow, 3 = both.
                            errorBuffer := or(
                                errorBuffer,
                                or(
                                    shl(1, lt(newAmount, amount)),
                                    iszero(mload(amountPtr))
                                )
                            )
                            // Update the amount to the new, summed amount.
                            amount := newAmount
                            // Zero out original item amount to indicate it is credited.
                            mstore(amountPtr, 0)
                        }
                        // Retrieve ReceivedItem pointer from Execution.
                        let receivedItem := mload(execution)
                        switch iszero(dataHash)
                        case 1 {
                            // On first valid item, populate the received item in
                            // memory for later comparison.
                            // Set the item type on the received item.
                            mstore(receivedItem, mload(considerationItemPtr))
                            // Set the token on the received item.
                            mstore(
                                add(receivedItem, Common_token_offset),
                                mload(add(considerationItemPtr, Common_token_offset))
                            )
                            // Set the identifier on the received item.
                            mstore(
                                add(receivedItem, Common_identifier_offset),
                                mload(
                                    add(considerationItemPtr, Common_identifier_offset)
                                )
                            )
                            // Set the recipient on the received item. Note that this
                            // depends on the memory layout established by the
                            // _validateOrdersAndPrepareToFulfill function.
                            mstore(
                                add(receivedItem, ReceivedItem_recipient_offset),
                                mload(
                                    add(
                                        considerationItemPtr,
                                        ReceivedItem_recipient_offset
                                    )
                                )
                            )
                            // Set provided offerer on the execution.
                            mstore(add(execution, Execution_offerer_offset), offerer)
                            // Set provided conduitKey on the execution.
                            mstore(add(execution, Execution_conduit_offset), conduitKey)
                            // Calculate the hash of (itemType, token, identifier,
                            // recipient). This is run after amount is set to zero, so
                            // there will be one blank word after identifier included in
                            // the hash buffer.
                            dataHash := keccak256(
                                considerationItemPtr,
                                ReceivedItem_size
                            )
                            // If component index > 0, swap component pointer with
                            // pointer to first component so that any remainder after
                            // fulfillment can be added back to the first item.
                            let firstFulfillmentHeadPtr := add(
                                considerationComponents,
                                OneWord
                            )
                            if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) {
                                let fulfillmentPtr := mload(fulfillmentHeadPtr)
                                mstore(firstFulfillmentHeadPtr, fulfillmentPtr)
                            }
                        }
                        default {
                            // Compare every subsequent item to the first; the item
                            // type, token, identifier and recipient must match.
                            if xor(
                                dataHash,
                                // Calculate the hash of (itemType, token, identifier,
                                // recipient). This is run after amount is set to zero,
                                // so there will be one blank word after identifier
                                // included in the hash buffer.
                                keccak256(considerationItemPtr, ReceivedItem_size)
                            ) {
                                // Throw if any of the requirements are not met.
                                throwInvalidFulfillmentComponentData()
                            }
                        }
                    }
                    // Retrieve ReceivedItem pointer from Execution.
                    let receivedItem := mload(execution)
                    // Write final amount to execution.
                    mstore(add(receivedItem, Common_amount_offset), amount)
                    // Determine whether the error buffer contains a nonzero error code.
                    if errorBuffer {
                        // If errorBuffer is 1, an item had an amount of zero.
                        if eq(errorBuffer, 1) {
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, MissingItemAmount_error_selector)
                            // revert(abi.encodeWithSignature("MissingItemAmount()"))
                            revert(
                                Error_selector_offset,
                                MissingItemAmount_error_length
                            )
                        }
                        // If errorBuffer is not 1 or 0, `amount` overflowed.
                        // Panic!
                        throwOverflow()
                    }
                    // Declare function for reverts on invalid fulfillment data.
                    function throwInvalidFulfillmentComponentData() {
                        // Store the InvalidFulfillmentComponentData error signature.
                        mstore(0, InvalidFulfillmentComponentData_error_selector)
                        // revert(abi.encodeWithSignature(
                        //     "InvalidFulfillmentComponentData()"
                        // ))
                        revert(
                            Error_selector_offset,
                            InvalidFulfillmentComponentData_error_length
                        )
                    }
                    // Declare function for reverts due to arithmetic overflows.
                    function throwOverflow() {
                        // Store the Panic error signature.
                        mstore(0, Panic_error_selector)
                        // Store the arithmetic (0x11) panic code.
                        mstore(Panic_error_code_ptr, Panic_arithmetic)
                        // revert(abi.encodeWithSignature("Panic(uint256)", 0x11))
                        revert(Error_selector_offset, Panic_error_length)
                    }
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.17;
        import { Side } from "./ConsiderationEnums.sol";
        import {
            BadFraction_error_length,
            BadFraction_error_selector,
            CannotCancelOrder_error_length,
            CannotCancelOrder_error_selector,
            ConsiderationLengthNotEqualToTotalOriginal_error_length,
            ConsiderationLengthNotEqualToTotalOriginal_error_selector,
            ConsiderationNotMet_error_considerationIndex_ptr,
            ConsiderationNotMet_error_length,
            ConsiderationNotMet_error_orderIndex_ptr,
            ConsiderationNotMet_error_selector,
            ConsiderationNotMet_error_shortfallAmount_ptr,
            CriteriaNotEnabledForItem_error_length,
            CriteriaNotEnabledForItem_error_selector,
            Error_selector_offset,
            InsufficientNativeTokensSupplied_error_length,
            InsufficientNativeTokensSupplied_error_selector,
            InvalidBasicOrderParameterEncoding_error_length,
            InvalidBasicOrderParameterEncoding_error_selector,
            InvalidCallToConduit_error_conduit_ptr,
            InvalidCallToConduit_error_length,
            InvalidCallToConduit_error_selector,
            InvalidConduit_error_conduit_ptr,
            InvalidConduit_error_conduitKey_ptr,
            InvalidConduit_error_length,
            InvalidConduit_error_selector,
            InvalidContractOrder_error_length,
            InvalidContractOrder_error_orderHash_ptr,
            InvalidContractOrder_error_selector,
            InvalidERC721TransferAmount_error_amount_ptr,
            InvalidERC721TransferAmount_error_length,
            InvalidERC721TransferAmount_error_selector,
            InvalidMsgValue_error_length,
            InvalidMsgValue_error_selector,
            InvalidMsgValue_error_value_ptr,
            InvalidNativeOfferItem_error_length,
            InvalidNativeOfferItem_error_selector,
            InvalidProof_error_length,
            InvalidProof_error_selector,
            InvalidTime_error_endTime_ptr,
            InvalidTime_error_length,
            InvalidTime_error_selector,
            InvalidTime_error_startTime_ptr,
            MismatchedOfferAndConsiderationComponents_error_idx_ptr,
            MismatchedOfferAndConsiderationComponents_error_length,
            MismatchedOfferAndConsiderationComponents_error_selector,
            MissingFulfillmentComponentOnAggregation_error_length,
            MissingFulfillmentComponentOnAggregation_error_selector,
            MissingFulfillmentComponentOnAggregation_error_side_ptr,
            MissingOriginalConsiderationItems_error_length,
            MissingOriginalConsiderationItems_error_selector,
            NoReentrantCalls_error_length,
            NoReentrantCalls_error_selector,
            NoSpecifiedOrdersAvailable_error_length,
            NoSpecifiedOrdersAvailable_error_selector,
            OfferAndConsiderationRequiredOnFulfillment_error_length,
            OfferAndConsiderationRequiredOnFulfillment_error_selector,
            OrderAlreadyFilled_error_length,
            OrderAlreadyFilled_error_orderHash_ptr,
            OrderAlreadyFilled_error_selector,
            OrderCriteriaResolverOutOfRange_error_length,
            OrderCriteriaResolverOutOfRange_error_selector,
            OrderCriteriaResolverOutOfRange_error_side_ptr,
            OrderIsCancelled_error_length,
            OrderIsCancelled_error_orderHash_ptr,
            OrderIsCancelled_error_selector,
            OrderPartiallyFilled_error_length,
            OrderPartiallyFilled_error_orderHash_ptr,
            OrderPartiallyFilled_error_selector,
            PartialFillsNotEnabledForOrder_error_length,
            PartialFillsNotEnabledForOrder_error_selector,
            UnresolvedConsiderationCriteria_error_length,
            UnresolvedConsiderationCriteria_error_orderIndex_ptr,
            UnresolvedConsiderationCriteria_error_selector,
            UnresolvedOfferCriteria_error_length,
            UnresolvedOfferCriteria_error_offerIndex_ptr,
            UnresolvedOfferCriteria_error_orderIndex_ptr,
            UnresolvedOfferCriteria_error_selector,
            UnusedItemParameters_error_length,
            UnusedItemParameters_error_selector
        } from "./ConsiderationErrorConstants.sol";
        /**
         * @dev Reverts the current transaction with a "BadFraction" error message.
         */
        function _revertBadFraction() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, BadFraction_error_selector)
                // revert(abi.encodeWithSignature("BadFraction()"))
                revert(Error_selector_offset, BadFraction_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with a "ConsiderationNotMet" error
         *      message, including the provided order index, consideration index, and
         *      shortfall amount.
         *
         * @param orderIndex         The index of the order that did not meet the
         *                           consideration criteria.
         * @param considerationIndex The index of the consideration item that did not
         *                           meet its criteria.
         * @param shortfallAmount    The amount by which the consideration criteria were
         *                           not met.
         */
        function _revertConsiderationNotMet(
            uint256 orderIndex,
            uint256 considerationIndex,
            uint256 shortfallAmount
        ) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, ConsiderationNotMet_error_selector)
                // Store arguments.
                mstore(ConsiderationNotMet_error_orderIndex_ptr, orderIndex)
                mstore(
                    ConsiderationNotMet_error_considerationIndex_ptr, considerationIndex
                )
                mstore(ConsiderationNotMet_error_shortfallAmount_ptr, shortfallAmount)
                // revert(abi.encodeWithSignature(
                //     "ConsiderationNotMet(uint256,uint256,uint256)",
                //     orderIndex,
                //     considerationIndex,
                //     shortfallAmount
                // ))
                revert(Error_selector_offset, ConsiderationNotMet_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with a "CriteriaNotEnabledForItem" error
         *      message.
         */
        function _revertCriteriaNotEnabledForItem() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, CriteriaNotEnabledForItem_error_selector)
                // revert(abi.encodeWithSignature("CriteriaNotEnabledForItem()"))
                revert(Error_selector_offset, CriteriaNotEnabledForItem_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an
         *      "InsufficientNativeTokensSupplied" error message.
         */
        function _revertInsufficientNativeTokensSupplied() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InsufficientNativeTokensSupplied_error_selector)
                // revert(abi.encodeWithSignature("InsufficientNativeTokensSupplied()"))
                revert(
                    Error_selector_offset, InsufficientNativeTokensSupplied_error_length
                )
            }
        }
        /**
         * @dev Reverts the current transaction with an
         *      "InvalidBasicOrderParameterEncoding" error message.
         */
        function _revertInvalidBasicOrderParameterEncoding() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidBasicOrderParameterEncoding_error_selector)
                // revert(abi.encodeWithSignature(
                //     "InvalidBasicOrderParameterEncoding()"
                // ))
                revert(
                    Error_selector_offset,
                    InvalidBasicOrderParameterEncoding_error_length
                )
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidCallToConduit" error
         *      message, including the provided address of the conduit that was called
         *      improperly.
         *
         * @param conduit The address of the conduit that was called improperly.
         */
        function _revertInvalidCallToConduit(address conduit) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidCallToConduit_error_selector)
                // Store argument.
                mstore(InvalidCallToConduit_error_conduit_ptr, conduit)
                // revert(abi.encodeWithSignature(
                //     "InvalidCallToConduit(address)",
                //     conduit
                // ))
                revert(Error_selector_offset, InvalidCallToConduit_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "CannotCancelOrder" error
         *      message.
         */
        function _revertCannotCancelOrder() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, CannotCancelOrder_error_selector)
                // revert(abi.encodeWithSignature("CannotCancelOrder()"))
                revert(Error_selector_offset, CannotCancelOrder_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidConduit" error message,
         *      including the provided key and address of the invalid conduit.
         *
         * @param conduitKey    The key of the invalid conduit.
         * @param conduit       The address of the invalid conduit.
         */
        function _revertInvalidConduit(bytes32 conduitKey, address conduit) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidConduit_error_selector)
                // Store arguments.
                mstore(InvalidConduit_error_conduitKey_ptr, conduitKey)
                mstore(InvalidConduit_error_conduit_ptr, conduit)
                // revert(abi.encodeWithSignature(
                //     "InvalidConduit(bytes32,address)",
                //     conduitKey,
                //     conduit
                // ))
                revert(Error_selector_offset, InvalidConduit_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidERC721TransferAmount"
         *      error message.
         *
         * @param amount The invalid amount.
         */
        function _revertInvalidERC721TransferAmount(uint256 amount) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidERC721TransferAmount_error_selector)
                // Store argument.
                mstore(InvalidERC721TransferAmount_error_amount_ptr, amount)
                // revert(abi.encodeWithSignature(
                //     "InvalidERC721TransferAmount(uint256)",
                //     amount
                // ))
                revert(Error_selector_offset, InvalidERC721TransferAmount_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidMsgValue" error message,
         *      including the invalid value that was sent in the transaction's
         *      `msg.value` field.
         *
         * @param value The invalid value that was sent in the transaction's `msg.value`
         *              field.
         */
        function _revertInvalidMsgValue(uint256 value) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidMsgValue_error_selector)
                // Store argument.
                mstore(InvalidMsgValue_error_value_ptr, value)
                // revert(abi.encodeWithSignature("InvalidMsgValue(uint256)", value))
                revert(Error_selector_offset, InvalidMsgValue_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidNativeOfferItem" error
         *      message.
         */
        function _revertInvalidNativeOfferItem() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidNativeOfferItem_error_selector)
                // revert(abi.encodeWithSignature("InvalidNativeOfferItem()"))
                revert(Error_selector_offset, InvalidNativeOfferItem_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidProof" error message.
         */
        function _revertInvalidProof() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidProof_error_selector)
                // revert(abi.encodeWithSignature("InvalidProof()"))
                revert(Error_selector_offset, InvalidProof_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidContractOrder" error
         *      message.
         *
         * @param orderHash The hash of the contract order that caused the error.
         */
        function _revertInvalidContractOrder(bytes32 orderHash) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidContractOrder_error_selector)
                // Store arguments.
                mstore(InvalidContractOrder_error_orderHash_ptr, orderHash)
                // revert(abi.encodeWithSignature(
                //     "InvalidContractOrder(bytes32)",
                //     orderHash
                // ))
                revert(Error_selector_offset, InvalidContractOrder_error_length)
            }
        }
        /**
         * @dev Reverts the current transaction with an "InvalidTime" error message.
         *
         * @param startTime       The time at which the order becomes active.
         * @param endTime         The time at which the order becomes inactive.
         */
        function _revertInvalidTime(uint256 startTime, uint256 endTime) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, InvalidTime_error_selector)
                // Store arguments.
                mstore(InvalidTime_error_startTime_ptr, startTime)
                mstore(InvalidTime_error_endTime_ptr, endTime)
                // revert(abi.encodeWithSignature(
                //     "InvalidTime(uint256,uint256)",
                //     startTime,
                //     endTime
                // ))
                revert(Error_selector_offset, InvalidTime_error_length)
            }
        }
        /**
         * @dev Reverts execution with a "MissingFulfillmentComponentOnAggregation"
         *       error message.
         *
         * @param side The side of the fulfillment component that is missing (0 for
         *             offer, 1 for consideration).
         *
         */
        function _revertMissingFulfillmentComponentOnAggregation(Side side) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, MissingFulfillmentComponentOnAggregation_error_selector)
                // Store argument.
                mstore(MissingFulfillmentComponentOnAggregation_error_side_ptr, side)
                // revert(abi.encodeWithSignature(
                //     "MissingFulfillmentComponentOnAggregation(uint8)",
                //     side
                // ))
                revert(
                    Error_selector_offset,
                    MissingFulfillmentComponentOnAggregation_error_length
                )
            }
        }
        /**
         * @dev Reverts execution with a "MissingOriginalConsiderationItems" error
         *      message.
         */
        function _revertMissingOriginalConsiderationItems() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, MissingOriginalConsiderationItems_error_selector)
                // revert(abi.encodeWithSignature(
                //     "MissingOriginalConsiderationItems()"
                // ))
                revert(
                    Error_selector_offset,
                    MissingOriginalConsiderationItems_error_length
                )
            }
        }
        /**
         * @dev Reverts execution with a "NoReentrantCalls" error message.
         */
        function _revertNoReentrantCalls() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, NoReentrantCalls_error_selector)
                // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                revert(Error_selector_offset, NoReentrantCalls_error_length)
            }
        }
        /**
         * @dev Reverts execution with a "NoSpecifiedOrdersAvailable" error message.
         */
        function _revertNoSpecifiedOrdersAvailable() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, NoSpecifiedOrdersAvailable_error_selector)
                // revert(abi.encodeWithSignature("NoSpecifiedOrdersAvailable()"))
                revert(Error_selector_offset, NoSpecifiedOrdersAvailable_error_length)
            }
        }
        /**
         * @dev Reverts execution with an "OrderAlreadyFilled" error message.
         *
         * @param orderHash The hash of the order that has already been filled.
         */
        function _revertOrderAlreadyFilled(bytes32 orderHash) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, OrderAlreadyFilled_error_selector)
                // Store argument.
                mstore(OrderAlreadyFilled_error_orderHash_ptr, orderHash)
                // revert(abi.encodeWithSignature(
                //     "OrderAlreadyFilled(bytes32)",
                //     orderHash
                // ))
                revert(Error_selector_offset, OrderAlreadyFilled_error_length)
            }
        }
        /**
         * @dev Reverts execution with an "OrderCriteriaResolverOutOfRange" error
         *      message.
         *
         * @param side The side of the criteria that is missing (0 for offer, 1 for
         *             consideration).
         *
         */
        function _revertOrderCriteriaResolverOutOfRange(Side side) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, OrderCriteriaResolverOutOfRange_error_selector)
                // Store argument.
                mstore(OrderCriteriaResolverOutOfRange_error_side_ptr, side)
                // revert(abi.encodeWithSignature(
                //     "OrderCriteriaResolverOutOfRange(uint8)",
                //     side
                // ))
                revert(
                    Error_selector_offset, OrderCriteriaResolverOutOfRange_error_length
                )
            }
        }
        /**
         * @dev Reverts execution with an "OrderIsCancelled" error message.
         *
         * @param orderHash The hash of the order that has already been cancelled.
         */
        function _revertOrderIsCancelled(bytes32 orderHash) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, OrderIsCancelled_error_selector)
                // Store argument.
                mstore(OrderIsCancelled_error_orderHash_ptr, orderHash)
                // revert(abi.encodeWithSignature(
                //     "OrderIsCancelled(bytes32)",
                //     orderHash
                // ))
                revert(Error_selector_offset, OrderIsCancelled_error_length)
            }
        }
        /**
         * @dev Reverts execution with an "OrderPartiallyFilled" error message.
         *
         * @param orderHash The hash of the order that has already been partially
         *                  filled.
         */
        function _revertOrderPartiallyFilled(bytes32 orderHash) pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, OrderPartiallyFilled_error_selector)
                // Store argument.
                mstore(OrderPartiallyFilled_error_orderHash_ptr, orderHash)
                // revert(abi.encodeWithSignature(
                //     "OrderPartiallyFilled(bytes32)",
                //     orderHash
                // ))
                revert(Error_selector_offset, OrderPartiallyFilled_error_length)
            }
        }
        /**
         * @dev Reverts execution with a "PartialFillsNotEnabledForOrder" error message.
         */
        function _revertPartialFillsNotEnabledForOrder() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, PartialFillsNotEnabledForOrder_error_selector)
                // revert(abi.encodeWithSignature("PartialFillsNotEnabledForOrder()"))
                revert(
                    Error_selector_offset, PartialFillsNotEnabledForOrder_error_length
                )
            }
        }
        /**
         * @dev Reverts execution with an "UnusedItemParameters" error message.
         */
        function _revertUnusedItemParameters() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, UnusedItemParameters_error_selector)
                // revert(abi.encodeWithSignature("UnusedItemParameters()"))
                revert(Error_selector_offset, UnusedItemParameters_error_length)
            }
        }
        /**
         * @dev Reverts execution with a "ConsiderationLengthNotEqualToTotalOriginal"
         *      error message.
         */
        function _revertConsiderationLengthNotEqualToTotalOriginal() pure {
            assembly {
                // Store left-padded selector with push4 (reduces bytecode),
                // mem[28:32] = selector
                mstore(0, ConsiderationLengthNotEqualToTotalOriginal_error_selector)
                // revert(abi.encodeWithSignature(
                //     "ConsiderationLengthNotEqualToTotalOriginal()"
                // ))
                revert(
                    Error_selector_offset,
                    ConsiderationLengthNotEqualToTotalOriginal_error_length
                )
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        uint256 constant Error_selector_offset = 0x1c;
        /*
         *  error MissingFulfillmentComponentOnAggregation(uint8 side)
         *    - Defined in FulfillmentApplicationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: side
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant MissingFulfillmentComponentOnAggregation_error_selector = (
            0x375c24c1
        );
        uint256 constant MissingFulfillmentComponentOnAggregation_error_side_ptr = 0x20;
        uint256 constant MissingFulfillmentComponentOnAggregation_error_length = 0x24;
        /*
         *  error OfferAndConsiderationRequiredOnFulfillment()
         *    - Defined in FulfillmentApplicationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_selector = (
            0x98e9db6e
        );
        uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_length = 0x04;
        /*
         *  error MismatchedFulfillmentOfferAndConsiderationComponents(
         *      uint256 fulfillmentIndex
         *  )
         *    - Defined in FulfillmentApplicationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: fulfillmentIndex
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant MismatchedOfferAndConsiderationComponents_error_selector = (
            0xbced929d
        );
        uint256 constant MismatchedOfferAndConsiderationComponents_error_idx_ptr = 0x20;
        uint256 constant MismatchedOfferAndConsiderationComponents_error_length = 0x24;
        /*
         *  error InvalidFulfillmentComponentData()
         *    - Defined in FulfillmentApplicationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidFulfillmentComponentData_error_selector = 0x7fda7279;
        uint256 constant InvalidFulfillmentComponentData_error_length = 0x04;
        /*
         *  error InexactFraction()
         *    - Defined in AmountDerivationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InexactFraction_error_selector = 0xc63cf089;
        uint256 constant InexactFraction_error_length = 0x04;
        /*
         *  error OrderCriteriaResolverOutOfRange(uint8 side)
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: side
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant OrderCriteriaResolverOutOfRange_error_selector = 0x133c37c6;
        uint256 constant OrderCriteriaResolverOutOfRange_error_side_ptr = 0x20;
        uint256 constant OrderCriteriaResolverOutOfRange_error_length = 0x24;
        /*
         *  error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex)
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderIndex
         *    - 0x40: offerIndex
         * Revert buffer is memory[0x1c:0x60]
         */
        uint256 constant UnresolvedOfferCriteria_error_selector = 0xd6929332;
        uint256 constant UnresolvedOfferCriteria_error_orderIndex_ptr = 0x20;
        uint256 constant UnresolvedOfferCriteria_error_offerIndex_ptr = 0x40;
        uint256 constant UnresolvedOfferCriteria_error_length = 0x44;
        /*
         *  error UnresolvedConsiderationCriteria(
         *      uint256 orderIndex,
         *      uint256 considerationIndex
         *  )
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderIndex
         *    - 0x40: considerationIndex
         * Revert buffer is memory[0x1c:0x60]
         */
        uint256 constant UnresolvedConsiderationCriteria_error_selector = 0xa8930e9a;
        uint256 constant UnresolvedConsiderationCriteria_error_orderIndex_ptr = 0x20;
        uint256 constant UnresolvedConsiderationCriteria_error_itemIndex_ptr = 0x40;
        uint256 constant UnresolvedConsiderationCriteria_error_length = 0x44;
        /*
         *  error OfferCriteriaResolverOutOfRange()
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant OfferCriteriaResolverOutOfRange_error_selector = 0xbfb3f8ce;
        // uint256 constant OfferCriteriaResolverOutOfRange_error_length = 0x04;
        /*
         *  error ConsiderationCriteriaResolverOutOfRange()
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant ConsiderationCriteriaResolverOutOfRange_error_selector = (
            0x6088d7de
        );
        uint256 constant ConsiderationCriteriaResolverOutOfRange_err_selector = (
            0x6088d7de
        );
        // uint256 constant ConsiderationCriteriaResolverOutOfRange_error_length = 0x04;
        /*
         *  error CriteriaNotEnabledForItem()
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant CriteriaNotEnabledForItem_error_selector = 0x94eb6af6;
        uint256 constant CriteriaNotEnabledForItem_error_length = 0x04;
        /*
         *  error InvalidProof()
         *    - Defined in CriteriaResolutionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidProof_error_selector = 0x09bde339;
        uint256 constant InvalidProof_error_length = 0x04;
        /*
         *  error InvalidRestrictedOrder(bytes32 orderHash)
         *    - Defined in ZoneInteractionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderHash
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant InvalidRestrictedOrder_error_selector = 0xfb5014fc;
        uint256 constant InvalidRestrictedOrder_error_orderHash_ptr = 0x20;
        uint256 constant InvalidRestrictedOrder_error_length = 0x24;
        /*
         *  error InvalidContractOrder(bytes32 orderHash)
         *    - Defined in ZoneInteractionErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderHash
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant InvalidContractOrder_error_selector = 0x93979285;
        uint256 constant InvalidContractOrder_error_orderHash_ptr = 0x20;
        uint256 constant InvalidContractOrder_error_length = 0x24;
        /*
         *  error BadSignatureV(uint8 v)
         *    - Defined in SignatureVerificationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: v
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant BadSignatureV_error_selector = 0x1f003d0a;
        uint256 constant BadSignatureV_error_v_ptr = 0x20;
        uint256 constant BadSignatureV_error_length = 0x24;
        /*
         *  error InvalidSigner()
         *    - Defined in SignatureVerificationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidSigner_error_selector = 0x815e1d64;
        uint256 constant InvalidSigner_error_length = 0x04;
        /*
         *  error InvalidSignature()
         *    - Defined in SignatureVerificationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidSignature_error_selector = 0x8baa579f;
        uint256 constant InvalidSignature_error_length = 0x04;
        /*
         *  error BadContractSignature()
         *    - Defined in SignatureVerificationErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant BadContractSignature_error_selector = 0x4f7fb80d;
        uint256 constant BadContractSignature_error_length = 0x04;
        /*
         *  error InvalidERC721TransferAmount(uint256 amount)
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: amount
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant InvalidERC721TransferAmount_error_selector = 0x69f95827;
        uint256 constant InvalidERC721TransferAmount_error_amount_ptr = 0x20;
        uint256 constant InvalidERC721TransferAmount_error_length = 0x24;
        /*
         *  error MissingItemAmount()
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant MissingItemAmount_error_selector = 0x91b3e514;
        uint256 constant MissingItemAmount_error_length = 0x04;
        /*
         *  error UnusedItemParameters()
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant UnusedItemParameters_error_selector = 0x6ab37ce7;
        uint256 constant UnusedItemParameters_error_length = 0x04;
        /*
         *  error NoReentrantCalls()
         *    - Defined in ReentrancyErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant NoReentrantCalls_error_selector = 0x7fa8a987;
        uint256 constant NoReentrantCalls_error_length = 0x04;
        /*
         *  error OrderAlreadyFilled(bytes32 orderHash)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderHash
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant OrderAlreadyFilled_error_selector = 0x10fda3e1;
        uint256 constant OrderAlreadyFilled_error_orderHash_ptr = 0x20;
        uint256 constant OrderAlreadyFilled_error_length = 0x24;
        /*
         *  error InvalidTime(uint256 startTime, uint256 endTime)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: startTime
         *    - 0x40: endTime
         * Revert buffer is memory[0x1c:0x60]
         */
        uint256 constant InvalidTime_error_selector = 0x21ccfeb7;
        uint256 constant InvalidTime_error_startTime_ptr = 0x20;
        uint256 constant InvalidTime_error_endTime_ptr = 0x40;
        uint256 constant InvalidTime_error_length = 0x44;
        /*
         *  error InvalidConduit(bytes32 conduitKey, address conduit)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: conduitKey
         *    - 0x40: conduit
         * Revert buffer is memory[0x1c:0x60]
         */
        uint256 constant InvalidConduit_error_selector = 0x1cf99b26;
        uint256 constant InvalidConduit_error_conduitKey_ptr = 0x20;
        uint256 constant InvalidConduit_error_conduit_ptr = 0x40;
        uint256 constant InvalidConduit_error_length = 0x44;
        /*
         *  error MissingOriginalConsiderationItems()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant MissingOriginalConsiderationItems_error_selector = 0x466aa616;
        uint256 constant MissingOriginalConsiderationItems_error_length = 0x04;
        /*
         *  error InvalidCallToConduit(address conduit)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: conduit
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant InvalidCallToConduit_error_selector = 0xd13d53d4;
        uint256 constant InvalidCallToConduit_error_conduit_ptr = 0x20;
        uint256 constant InvalidCallToConduit_error_length = 0x24;
        /*
         *  error ConsiderationNotMet(
         *      uint256 orderIndex,
         *      uint256 considerationIndex,
         *      uint256 shortfallAmount
         *  )
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderIndex
         *    - 0x40: considerationIndex
         *    - 0x60: shortfallAmount
         * Revert buffer is memory[0x1c:0x80]
         */
        uint256 constant ConsiderationNotMet_error_selector = 0xa5f54208;
        uint256 constant ConsiderationNotMet_error_orderIndex_ptr = 0x20;
        uint256 constant ConsiderationNotMet_error_considerationIndex_ptr = 0x40;
        uint256 constant ConsiderationNotMet_error_shortfallAmount_ptr = 0x60;
        uint256 constant ConsiderationNotMet_error_length = 0x64;
        /*
         *  error InsufficientNativeTokensSupplied()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InsufficientNativeTokensSupplied_error_selector = 0x8ffff980;
        uint256 constant InsufficientNativeTokensSupplied_error_length = 0x04;
        /*
         *  error NativeTokenTransferGenericFailure(address account, uint256 amount)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: account
         *    - 0x40: amount
         * Revert buffer is memory[0x1c:0x60]
         */
        uint256 constant NativeTokenTransferGenericFailure_error_selector = 0xbc806b96;
        uint256 constant NativeTokenTransferGenericFailure_error_account_ptr = 0x20;
        uint256 constant NativeTokenTransferGenericFailure_error_amount_ptr = 0x40;
        uint256 constant NativeTokenTransferGenericFailure_error_length = 0x44;
        /*
         *  error PartialFillsNotEnabledForOrder()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant PartialFillsNotEnabledForOrder_error_selector = 0xa11b63ff;
        uint256 constant PartialFillsNotEnabledForOrder_error_length = 0x04;
        /*
         *  error OrderIsCancelled(bytes32 orderHash)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderHash
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant OrderIsCancelled_error_selector = 0x1a515574;
        uint256 constant OrderIsCancelled_error_orderHash_ptr = 0x20;
        uint256 constant OrderIsCancelled_error_length = 0x24;
        /*
         *  error OrderPartiallyFilled(bytes32 orderHash)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: orderHash
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant OrderPartiallyFilled_error_selector = 0xee9e0e63;
        uint256 constant OrderPartiallyFilled_error_orderHash_ptr = 0x20;
        uint256 constant OrderPartiallyFilled_error_length = 0x24;
        /*
         *  error CannotCancelOrder()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant CannotCancelOrder_error_selector = 0xfed398fc;
        uint256 constant CannotCancelOrder_error_length = 0x04;
        /*
         *  error BadFraction()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant BadFraction_error_selector = 0x5a052b32;
        uint256 constant BadFraction_error_length = 0x04;
        /*
         *  error InvalidMsgValue(uint256 value)
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: value
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant InvalidMsgValue_error_selector = 0xa61be9f0;
        uint256 constant InvalidMsgValue_error_value_ptr = 0x20;
        uint256 constant InvalidMsgValue_error_length = 0x24;
        /*
         *  error InvalidBasicOrderParameterEncoding()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidBasicOrderParameterEncoding_error_selector = 0x39f3e3fd;
        uint256 constant InvalidBasicOrderParameterEncoding_error_length = 0x04;
        /*
         *  error NoSpecifiedOrdersAvailable()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant NoSpecifiedOrdersAvailable_error_selector = 0xd5da9a1b;
        uint256 constant NoSpecifiedOrdersAvailable_error_length = 0x04;
        /*
         *  error InvalidNativeOfferItem()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant InvalidNativeOfferItem_error_selector = 0x12d3f5a3;
        uint256 constant InvalidNativeOfferItem_error_length = 0x04;
        /*
         *  error ConsiderationLengthNotEqualToTotalOriginal()
         *    - Defined in ConsiderationEventsAndErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         * Revert buffer is memory[0x1c:0x20]
         */
        uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_selector = (
            0x2165628a
        );
        uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_length = 0x04;
        /*
         *  error Panic(uint256 code)
         *    - Built-in Solidity error
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: code
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant Panic_error_selector = 0x4e487b71;
        uint256 constant Panic_error_code_ptr = 0x20;
        uint256 constant Panic_error_length = 0x24;
        uint256 constant Panic_arithmetic = 0x11;
        // uint256 constant Panic_resource = 0x41;
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            BasicOrderRouteType,
            ItemType,
            OrderType
        } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            BasicOrderParameters,
            OrderStatus
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { OrderValidator } from "./OrderValidator.sol";
        import {
            _revertInsufficientNativeTokensSupplied,
            _revertInvalidMsgValue,
            _revertInvalidERC721TransferAmount,
            _revertUnusedItemParameters
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            AccumulatorDisarmed,
            AdditionalRecipient_size_shift,
            AdditionalRecipient_size,
            BasicOrder_additionalRecipients_data_cdPtr,
            BasicOrder_addlRecipients_length_cdPtr,
            BasicOrder_basicOrderType_cdPtr,
            BasicOrder_common_params_size,
            BasicOrder_considerationAmount_cdPtr,
            BasicOrder_considerationHashesArray_ptr,
            BasicOrder_considerationIdentifier_cdPtr,
            BasicOrder_considerationItem_endAmount_ptr,
            BasicOrder_considerationItem_identifier_ptr,
            BasicOrder_considerationItem_itemType_ptr,
            BasicOrder_considerationItem_startAmount_ptr,
            BasicOrder_considerationItem_token_ptr,
            BasicOrder_considerationItem_typeHash_ptr,
            BasicOrder_considerationToken_cdPtr,
            BasicOrder_endTime_cdPtr,
            BasicOrder_fulfillerConduit_cdPtr,
            BasicOrder_offerAmount_cdPtr,
            BasicOrder_offeredItemByteMap,
            BasicOrder_offerer_cdPtr,
            BasicOrder_offererConduit_cdPtr,
            BasicOrder_offerIdentifier_cdPtr,
            BasicOrder_offerItem_endAmount_ptr,
            BasicOrder_offerItem_itemType_ptr,
            BasicOrder_offerItem_token_ptr,
            BasicOrder_offerItem_typeHash_ptr,
            BasicOrder_offerToken_cdPtr,
            BasicOrder_order_considerationHashes_ptr,
            BasicOrder_order_counter_ptr,
            BasicOrder_order_offerer_ptr,
            BasicOrder_order_offerHashes_ptr,
            BasicOrder_order_orderType_ptr,
            BasicOrder_order_startTime_ptr,
            BasicOrder_order_typeHash_ptr,
            BasicOrder_receivedItemByteMap,
            BasicOrder_startTime_cdPtr,
            BasicOrder_totalOriginalAdditionalRecipients_cdPtr,
            BasicOrder_zone_cdPtr,
            Common_token_offset,
            Conduit_execute_ConduitTransfer_length_ptr,
            Conduit_execute_ConduitTransfer_length,
            Conduit_execute_ConduitTransfer_offset_ptr,
            Conduit_execute_ConduitTransfer_ptr,
            Conduit_execute_signature,
            Conduit_execute_transferAmount_ptr,
            Conduit_execute_transferIdentifier_ptr,
            Conduit_execute_transferFrom_ptr,
            Conduit_execute_transferItemType_ptr,
            Conduit_execute_transferTo_ptr,
            Conduit_execute_transferToken_ptr,
            EIP712_ConsiderationItem_size,
            EIP712_OfferItem_size,
            EIP712_Order_size,
            FiveWords,
            FourWords,
            FreeMemoryPointerSlot,
            MaskOverLastTwentyBytes,
            OneConduitExecute_size,
            OneWord,
            OneWordShift,
            OrderFulfilled_baseOffset,
            OrderFulfilled_baseSize,
            OrderFulfilled_consideration_body_offset,
            OrderFulfilled_consideration_head_offset,
            OrderFulfilled_consideration_length_baseOffset,
            OrderFulfilled_fulfiller_offset,
            OrderFulfilled_offer_body_offset,
            OrderFulfilled_offer_head_offset,
            OrderFulfilled_offer_length_baseOffset,
            OrderFulfilled_offer_length_offset_relativeTo_baseOffset,
            OrderFulfilled_offer_itemType_offset_relativeTo_baseOffset,
            OrderFulfilled_offer_token_offset_relativeTo_baseOffset,
            OrderFulfilled_post_memory_region_reservedBytes,
            OrderFulfilled_selector,
            ReceivedItem_amount_offset,
            ReceivedItem_size,
            receivedItemsHash_ptr,
            ThreeWords,
            TwoWords,
            ZeroSlot
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            InvalidBasicOrderParameterEncoding_error_length,
            InvalidBasicOrderParameterEncoding_error_selector,
            InvalidTime_error_endTime_ptr,
            InvalidTime_error_length,
            InvalidTime_error_selector,
            InvalidTime_error_startTime_ptr,
            MissingOriginalConsiderationItems_error_length,
            MissingOriginalConsiderationItems_error_selector,
            UnusedItemParameters_error_length,
            UnusedItemParameters_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        import {
            CalldataPointer
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        /**
         * @title BasicOrderFulfiller
         * @author 0age
         * @notice BasicOrderFulfiller contains functionality for fulfilling "basic"
         *         orders with minimal overhead. See documentation for details on what
         *         qualifies as a basic order.
         */
        contract BasicOrderFulfiller is OrderValidator {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) OrderValidator(conduitController) {}
            /**
             * @dev Internal function to fulfill an order offering an ERC20, ERC721, or
             *      ERC1155 item by supplying Ether (or other native tokens), ERC20
             *      tokens, an ERC721 item, or an ERC1155 item as consideration. Six
             *      permutations are supported: Native token to ERC721, Native token to
             *      ERC1155, ERC20 to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and
             *      ERC1155 to ERC20 (with native tokens supplied as msg.value). For an
             *      order to be eligible for fulfillment via this method, it must
             *      contain a single offer item (though that item may have a greater
             *      amount if the item is not an ERC721). An arbitrary number of
             *      "additional recipients" may also be supplied which will each receive
             *      native tokens or ERC20 items from the fulfiller as consideration.
             *      Refer to the documentation for a more comprehensive summary of how
             *      to utilize this method and what orders are compatible with it.
             *
             * @return A boolean indicating whether the order has been fulfilled.
             */
            function _validateAndFulfillBasicOrder() internal returns (bool) {
                // Declare enums for order type & route to extract from basicOrderType.
                BasicOrderRouteType route;
                OrderType orderType;
                // Declare additional recipient item type to derive from the route type.
                ItemType additionalRecipientsItemType;
                bytes32 orderHash;
                // Utilize assembly to extract the order type and the basic order route.
                assembly {
                    // Read basicOrderType from calldata.
                    let basicOrderType := calldataload(BasicOrder_basicOrderType_cdPtr)
                    // Mask all but 2 least-significant bits to derive the order type.
                    orderType := and(basicOrderType, 3)
                    // Divide basicOrderType by four to derive the route.
                    route := shr(2, basicOrderType)
                    // If route > 1 additionalRecipient items are ERC20 (1) else native
                    // token (0).
                    additionalRecipientsItemType := gt(route, 1)
                }
                {
                    // Declare temporary variable for enforcing payable status.
                    bool correctPayableStatus;
                    // Utilize assembly to compare the route to the callvalue.
                    assembly {
                        // route 0 and 1 are payable, otherwise route is not payable.
                        correctPayableStatus := eq(
                            additionalRecipientsItemType,
                            iszero(callvalue())
                        )
                    }
                    // Revert if msg.value has not been supplied as part of payable
                    // routes or has been supplied as part of non-payable routes.
                    if (!correctPayableStatus) {
                        _revertInvalidMsgValue(msg.value);
                    }
                }
                // Declare more arguments that will be derived from route and calldata.
                address additionalRecipientsToken;
                ItemType offeredItemType;
                bool offerTypeIsAdditionalRecipientsType;
                uint256 callDataPointer;
                // Declare scope for received item type to manage stack pressure.
                {
                    ItemType receivedItemType;
                    // Utilize assembly to retrieve function arguments and cast types.
                    assembly {
                        // Check if offered item type == additional recipient item type.
                        offerTypeIsAdditionalRecipientsType := gt(route, 3)
                        // If route > 3 additionalRecipientsToken is at 0xc4 else 0x24.
                        additionalRecipientsToken := calldataload(
                            add(
                                BasicOrder_considerationToken_cdPtr,
                                mul(
                                    offerTypeIsAdditionalRecipientsType,
                                    BasicOrder_common_params_size
                                )
                            )
                        )
                        // If route > 2, receivedItemType is route - 2. If route is 2,
                        // the receivedItemType is ERC20 (1). Otherwise, it is native
                        // token (0).
                        receivedItemType := byte(route, BasicOrder_receivedItemByteMap)
                        // If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3,
                        // offeredItemType = route. Route is 0 or 1, it is route + 2.
                        offeredItemType := byte(route, BasicOrder_offeredItemByteMap)
                    }
                    // Derive & validate order using parameters and update order status.
                    (orderHash, callDataPointer) = _prepareBasicFulfillmentFromCalldata(
                        orderType,
                        receivedItemType,
                        additionalRecipientsItemType,
                        additionalRecipientsToken,
                        offeredItemType
                    );
                }
                // Declare conduitKey argument used by transfer functions.
                bytes32 conduitKey;
                // Utilize assembly to derive conduit (if relevant) based on route.
                assembly {
                    // use offerer conduit for routes 0-3, fulfiller conduit otherwise.
                    conduitKey := calldataload(
                        add(
                            BasicOrder_offererConduit_cdPtr,
                            shl(OneWordShift, offerTypeIsAdditionalRecipientsType)
                        )
                    )
                }
                // Transfer tokens based on the route.
                if (additionalRecipientsItemType == ItemType.NATIVE) {
                    // Ensure neither consideration token nor identifier are set. Note
                    // that dirty upper bits in the consideration token will still cause
                    // this error to be thrown.
                    assembly {
                        if or(
                            calldataload(BasicOrder_considerationToken_cdPtr),
                            calldataload(BasicOrder_considerationIdentifier_cdPtr)
                        ) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, UnusedItemParameters_error_selector)
                            // revert(abi.encodeWithSignature("UnusedItemParameters()"))
                            revert(
                                Error_selector_offset,
                                UnusedItemParameters_error_length
                            )
                        }
                    }
                    // Transfer the ERC721 or ERC1155 item, bypassing the accumulator.
                    _transferIndividual721Or1155Item(offeredItemType, conduitKey);
                    // Transfer native to recipients, return excess to caller & wrap up.
                    _transferNativeTokensAndFinalize();
                } else {
                    // Initialize an accumulator array. From this point forward, no new
                    // memory regions can be safely allocated until the accumulator is
                    // no longer being utilized, as the accumulator operates in an
                    // open-ended fashion from this memory pointer; existing memory may
                    // still be accessed and modified, however.
                    bytes memory accumulator = new bytes(AccumulatorDisarmed);
                    // Choose transfer method for ERC721 or ERC1155 item based on route.
                    if (route == BasicOrderRouteType.ERC20_TO_ERC721) {
                        // Transfer ERC721 to caller using offerer's conduit preference.
                        _transferERC721(
                            CalldataPointer
                                .wrap(BasicOrder_offerToken_cdPtr)
                                .readAddress(),
                            CalldataPointer
                                .wrap(BasicOrder_offerer_cdPtr)
                                .readAddress(),
                            msg.sender,
                            CalldataPointer
                                .wrap(BasicOrder_offerIdentifier_cdPtr)
                                .readUint256(),
                            CalldataPointer
                                .wrap(BasicOrder_offerAmount_cdPtr)
                                .readUint256(),
                            conduitKey,
                            accumulator
                        );
                    } else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) {
                        // Transfer ERC1155 to caller with offerer's conduit preference.
                        _transferERC1155(
                            CalldataPointer
                                .wrap(BasicOrder_offerToken_cdPtr)
                                .readAddress(),
                            CalldataPointer
                                .wrap(BasicOrder_offerer_cdPtr)
                                .readAddress(),
                            msg.sender,
                            CalldataPointer
                                .wrap(BasicOrder_offerIdentifier_cdPtr)
                                .readUint256(),
                            CalldataPointer
                                .wrap(BasicOrder_offerAmount_cdPtr)
                                .readUint256(),
                            conduitKey,
                            accumulator
                        );
                    } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) {
                        // Transfer ERC721 to offerer using caller's conduit preference.
                        _transferERC721(
                            CalldataPointer
                                .wrap(BasicOrder_considerationToken_cdPtr)
                                .readAddress(),
                            msg.sender,
                            CalldataPointer
                                .wrap(BasicOrder_offerer_cdPtr)
                                .readAddress(),
                            CalldataPointer
                                .wrap(BasicOrder_considerationIdentifier_cdPtr)
                                .readUint256(),
                            CalldataPointer
                                .wrap(BasicOrder_considerationAmount_cdPtr)
                                .readUint256(),
                            conduitKey,
                            accumulator
                        );
                    } else {
                        // route == BasicOrderRouteType.ERC1155_TO_ERC20
                        // Transfer ERC1155 to offerer with caller's conduit preference.
                        _transferERC1155(
                            CalldataPointer
                                .wrap(BasicOrder_considerationToken_cdPtr)
                                .readAddress(),
                            msg.sender,
                            CalldataPointer
                                .wrap(BasicOrder_offerer_cdPtr)
                                .readAddress(),
                            CalldataPointer
                                .wrap(BasicOrder_considerationIdentifier_cdPtr)
                                .readUint256(),
                            CalldataPointer
                                .wrap(BasicOrder_considerationAmount_cdPtr)
                                .readUint256(),
                            conduitKey,
                            accumulator
                        );
                    }
                    // Transfer ERC20 tokens to all recipients and wrap up.
                    _transferERC20AndFinalize(
                        offerTypeIsAdditionalRecipientsType,
                        accumulator
                    );
                    // Trigger any remaining accumulated transfers via call to conduit.
                    _triggerIfArmed(accumulator);
                }
                // Determine whether order is restricted and, if so, that it is valid.
                _assertRestrictedBasicOrderValidity(
                    orderHash,
                    orderType,
                    callDataPointer
                );
                // Clear the reentrancy guard.
                _clearReentrancyGuard();
                return true;
            }
            /**
             * @dev Internal function to prepare fulfillment of a basic order with
             *      manual calldata and memory access. This calculates the order hash,
             *      emits an OrderFulfilled event, and asserts basic order validity.
             *      Note that calldata offsets must be validated as this function
             *      accesses constant calldata pointers for dynamic types that match
             *      default ABI encoding, but valid ABI encoding can use arbitrary
             *      offsets. Checking that the offsets were produced by default encoding
             *      will ensure that other functions using Solidity's calldata accessors
             *      (which calculate pointers from the stored offsets) are reading the
             *      same data as the order hash is derived from. Also note that this
             *      function accesses memory directly.
             *
             * @param orderType                    The order type.
             * @param receivedItemType             The item type of the initial
             *                                     consideration item on the order.
             * @param additionalRecipientsItemType The item type of any additional
             *                                     consideration item on the order.
             * @param additionalRecipientsToken    The ERC20 token contract address (if
             *                                     applicable) for any additional
             *                                     consideration item on the order.
             * @param offeredItemType              The item type of the offered item on
             *                                     the order.
             * @return orderHash The calculated order hash.
             */
            function _prepareBasicFulfillmentFromCalldata(
                OrderType orderType,
                ItemType receivedItemType,
                ItemType additionalRecipientsItemType,
                address additionalRecipientsToken,
                ItemType offeredItemType
            ) internal returns (bytes32 orderHash, uint256 callDataPointer) {
                // Ensure this function cannot be triggered during a reentrant call.
                _setReentrancyGuard(false); // Native tokens rejected during execution.
                // Verify that calldata offsets for all dynamic types were produced by
                // default encoding. This ensures that the constants used for calldata
                // pointers to dynamic types are the same as those calculated by
                // Solidity using their offsets. Also verify that the basic order type
                // is within range.
                _assertValidBasicOrderParameters();
                // Check for invalid time and missing original consideration items.
                // Utilize assembly so that constant calldata pointers can be applied.
                assembly {
                    // Ensure current timestamp is between order start time & end time.
                    if or(
                        gt(calldataload(BasicOrder_startTime_cdPtr), timestamp()),
                        iszero(gt(calldataload(BasicOrder_endTime_cdPtr), timestamp()))
                    ) {
                        // Store left-padded selector with push4 (reduces bytecode),
                        // mem[28:32] = selector
                        mstore(0, InvalidTime_error_selector)
                        // Store arguments.
                        mstore(
                            InvalidTime_error_startTime_ptr,
                            calldataload(BasicOrder_startTime_cdPtr)
                        )
                        mstore(
                            InvalidTime_error_endTime_ptr,
                            calldataload(BasicOrder_endTime_cdPtr)
                        )
                        // revert(abi.encodeWithSignature(
                        //     "InvalidTime(uint256,uint256)",
                        //     startTime,
                        //     endTime
                        // ))
                        revert(Error_selector_offset, InvalidTime_error_length)
                    }
                    // Ensure consideration array length isn't less than total original.
                    if lt(
                        calldataload(BasicOrder_addlRecipients_length_cdPtr),
                        calldataload(BasicOrder_totalOriginalAdditionalRecipients_cdPtr)
                    ) {
                        // Store left-padded selector with push4 (reduces bytecode),
                        // mem[28:32] = selector
                        mstore(0, MissingOriginalConsiderationItems_error_selector)
                        // revert(abi.encodeWithSignature(
                        //     "MissingOriginalConsiderationItems()"
                        // ))
                        revert(
                            Error_selector_offset,
                            MissingOriginalConsiderationItems_error_length
                        )
                    }
                }
                {
                    /**
                     * First, handle consideration items. Memory Layout:
                     *  0x60: final hash of the array of consideration item hashes
                     *  0x80-0x160: reused space for EIP712 hashing of each item
                     *   - 0x80: ConsiderationItem EIP-712 typehash (constant)
                     *   - 0xa0: itemType
                     *   - 0xc0: token
                     *   - 0xe0: identifier
                     *   - 0x100: startAmount
                     *   - 0x120: endAmount
                     *   - 0x140: recipient
                     *  0x160-END_ARR: array of consideration item hashes
                     *   - 0x160: primary consideration item EIP712 hash
                     *   - 0x180-END_ARR: additional recipient item EIP712 hashes
                     *  END_ARR: beginning of data for OrderFulfilled event
                     *   - END_ARR + 0x120: length of ReceivedItem array
                     *   - END_ARR + 0x140: beginning of data for first ReceivedItem
                     * (Note: END_ARR = 0x180 + RECIPIENTS_LENGTH * 0x20)
                     */
                    // Load consideration item typehash from runtime and place on stack.
                    bytes32 typeHash = _CONSIDERATION_ITEM_TYPEHASH;
                    // Utilize assembly to enable reuse of memory regions and use
                    // constant pointers when possible.
                    assembly {
                        /*
                         * 1. Calculate the EIP712 ConsiderationItem hash for the
                         * primary consideration item of the basic order.
                         */
                        // Write ConsiderationItem type hash and item type to memory.
                        mstore(BasicOrder_considerationItem_typeHash_ptr, typeHash)
                        mstore(
                            BasicOrder_considerationItem_itemType_ptr,
                            receivedItemType
                        )
                        // Copy calldata region with (token, identifier, amount) from
                        // BasicOrderParameters to ConsiderationItem. The
                        // considerationAmount is written to startAmount and endAmount
                        // as basic orders do not have dynamic amounts.
                        calldatacopy(
                            BasicOrder_considerationItem_token_ptr,
                            BasicOrder_considerationToken_cdPtr,
                            ThreeWords
                        )
                        // Copy calldata region with considerationAmount and offerer
                        // from BasicOrderParameters to endAmount and recipient in
                        // ConsiderationItem.
                        calldatacopy(
                            BasicOrder_considerationItem_endAmount_ptr,
                            BasicOrder_considerationAmount_cdPtr,
                            TwoWords
                        )
                        // Calculate EIP712 ConsiderationItem hash and store it in the
                        // array of EIP712 consideration hashes.
                        mstore(
                            BasicOrder_considerationHashesArray_ptr,
                            keccak256(
                                BasicOrder_considerationItem_typeHash_ptr,
                                EIP712_ConsiderationItem_size
                            )
                        )
                        /*
                         * 2. Write a ReceivedItem struct for the primary consideration
                         * item to the consideration array in OrderFulfilled.
                         */
                        // Get the additional recipients array length from calldata.
                        // This variable will later be repurposed to track the total
                        // original additional recipients instead of the total supplied.
                        let totalAdditionalRecipients := calldataload(
                            BasicOrder_addlRecipients_length_cdPtr
                        )
                        // Calculate pointer to length of OrderFulfilled consideration
                        // array. Note that this is based on total original additional
                        // recipients and not the supplied additional recipients, since
                        // the pointer only needs to be offset based on the size of the
                        // EIP-712 hashes used to derive the order hash (and the order
                        // hash does not take tips into account as part of derivation).
                        let eventConsiderationArrPtr := add(
                            OrderFulfilled_consideration_length_baseOffset,
                            shl(
                                OneWordShift,
                                calldataload(
                                    BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                                )
                            )
                        )
                        // Set the length of the consideration array to the number of
                        // additional recipients, plus one for the primary consideration
                        // item.
                        mstore(
                            eventConsiderationArrPtr,
                            add(totalAdditionalRecipients, 1)
                        )
                        // Overwrite the consideration array pointer so it points to the
                        // body of the first element
                        eventConsiderationArrPtr := add(
                            eventConsiderationArrPtr,
                            OneWord
                        )
                        // Set itemType at start of the ReceivedItem memory region.
                        mstore(eventConsiderationArrPtr, receivedItemType)
                        // Copy calldata region (token, identifier, amount & recipient)
                        // from BasicOrderParameters to ReceivedItem memory.
                        calldatacopy(
                            add(eventConsiderationArrPtr, Common_token_offset),
                            BasicOrder_considerationToken_cdPtr,
                            FourWords
                        )
                        /*
                         * 3. Calculate EIP712 ConsiderationItem hashes for original
                         * additional recipients and add a ReceivedItem for each to the
                         * consideration array in the OrderFulfilled event. The original
                         * additional recipients are all the consideration items signed
                         * by the offerer aside from the primary consideration items of
                         * the order. Uses memory region from 0x80-0x160 as a buffer for
                         * calculating EIP712 ConsiderationItem hashes.
                         */
                        // Put pointer to consideration hashes array on the stack.
                        // This will be updated as each additional recipient is hashed
                        let
                            considerationHashesPtr
                        := BasicOrder_considerationHashesArray_ptr
                        // Write item type, token, & identifier for additional recipient
                        // to memory region for hashing EIP712 ConsiderationItem; these
                        // values will be reused for each recipient.
                        mstore(
                            BasicOrder_considerationItem_itemType_ptr,
                            additionalRecipientsItemType
                        )
                        mstore(
                            BasicOrder_considerationItem_token_ptr,
                            additionalRecipientsToken
                        )
                        mstore(BasicOrder_considerationItem_identifier_ptr, 0)
                        // Declare a stack variable where all additional recipients will
                        // be combined to guard against providing dirty upper bits.
                        let combinedAdditionalRecipients
                        // Only iterate over the total original additional recipients
                        // (not the total supplied additional recipients) when deriving
                        // the order hash.
                        totalAdditionalRecipients := calldataload(
                            BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                        )
                        let i := 0
                        for {
                        } lt(i, totalAdditionalRecipients) {
                            i := add(i, 1)
                        } {
                            /*
                             * Calculate EIP712 ConsiderationItem hash for recipient.
                             */
                            // Retrieve calldata pointer for additional recipient.
                            let additionalRecipientCdPtr := add(
                                BasicOrder_additionalRecipients_data_cdPtr,
                                mul(AdditionalRecipient_size, i)
                            )
                            // Copy startAmount from calldata to the ConsiderationItem
                            // struct.
                            calldatacopy(
                                BasicOrder_considerationItem_startAmount_ptr,
                                additionalRecipientCdPtr,
                                OneWord
                            )
                            // Copy endAmount and recipient from calldata to the
                            // ConsiderationItem struct.
                            calldatacopy(
                                BasicOrder_considerationItem_endAmount_ptr,
                                additionalRecipientCdPtr,
                                AdditionalRecipient_size
                            )
                            // Include the recipient as part of combined recipients.
                            combinedAdditionalRecipients := or(
                                combinedAdditionalRecipients,
                                calldataload(add(additionalRecipientCdPtr, OneWord))
                            )
                            // Add 1 word to the pointer as part of each loop to reduce
                            // operations needed to get local offset into the array.
                            considerationHashesPtr := add(
                                considerationHashesPtr,
                                OneWord
                            )
                            // Calculate EIP712 ConsiderationItem hash and store it in
                            // the array of consideration hashes.
                            mstore(
                                considerationHashesPtr,
                                keccak256(
                                    BasicOrder_considerationItem_typeHash_ptr,
                                    EIP712_ConsiderationItem_size
                                )
                            )
                            /*
                             * Write ReceivedItem to OrderFulfilled data.
                             */
                            // At this point, eventConsiderationArrPtr points to the
                            // beginning of the ReceivedItem struct of the previous
                            // element in the array. Increase it by the size of the
                            // struct to arrive at the pointer for the current element.
                            eventConsiderationArrPtr := add(
                                eventConsiderationArrPtr,
                                ReceivedItem_size
                            )
                            // Write itemType to the ReceivedItem struct.
                            mstore(
                                eventConsiderationArrPtr,
                                additionalRecipientsItemType
                            )
                            // Write token to the next word of the ReceivedItem struct.
                            mstore(
                                add(eventConsiderationArrPtr, OneWord),
                                additionalRecipientsToken
                            )
                            // Copy endAmount & recipient words to ReceivedItem struct.
                            calldatacopy(
                                add(
                                    eventConsiderationArrPtr,
                                    ReceivedItem_amount_offset
                                ),
                                additionalRecipientCdPtr,
                                TwoWords
                            )
                        }
                        /*
                         * 4. Hash packed array of ConsiderationItem EIP712 hashes:
                         *   `keccak256(abi.encodePacked(receivedItemHashes))`
                         * Note that it is set at 0x60 — all other memory begins at
                         * 0x80. 0x60 is the "zero slot" and will be restored at the end
                         * of the assembly section and before required by the compiler.
                         */
                        mstore(
                            receivedItemsHash_ptr,
                            keccak256(
                                BasicOrder_considerationHashesArray_ptr,
                                shl(OneWordShift, add(totalAdditionalRecipients, 1))
                            )
                        )
                        /*
                         * 5. Add a ReceivedItem for each tip to the consideration array
                         * in the OrderFulfilled event. The tips are all the
                         * consideration items that were not signed by the offerer and
                         * were provided by the fulfiller.
                         */
                        // Overwrite length to length of the additionalRecipients array.
                        totalAdditionalRecipients := calldataload(
                            BasicOrder_addlRecipients_length_cdPtr
                        )
                        for {
                        } lt(i, totalAdditionalRecipients) {
                            i := add(i, 1)
                        } {
                            // Retrieve calldata pointer for additional recipient.
                            let additionalRecipientCdPtr := add(
                                BasicOrder_additionalRecipients_data_cdPtr,
                                mul(AdditionalRecipient_size, i)
                            )
                            // At this point, eventConsiderationArrPtr points to the
                            // beginning of the ReceivedItem struct of the previous
                            // element in the array. Increase it by the size of the
                            // struct to arrive at the pointer for the current element.
                            eventConsiderationArrPtr := add(
                                eventConsiderationArrPtr,
                                ReceivedItem_size
                            )
                            // Write itemType to the ReceivedItem struct.
                            mstore(
                                eventConsiderationArrPtr,
                                additionalRecipientsItemType
                            )
                            // Write token to the next word of the ReceivedItem struct.
                            mstore(
                                add(eventConsiderationArrPtr, OneWord),
                                additionalRecipientsToken
                            )
                            // Copy endAmount & recipient words to ReceivedItem struct.
                            calldatacopy(
                                add(
                                    eventConsiderationArrPtr,
                                    ReceivedItem_amount_offset
                                ),
                                additionalRecipientCdPtr,
                                TwoWords
                            )
                            // Include the recipient as part of combined recipients.
                            combinedAdditionalRecipients := or(
                                combinedAdditionalRecipients,
                                calldataload(add(additionalRecipientCdPtr, OneWord))
                            )
                        }
                        // Ensure no dirty upper bits on combined additional recipients.
                        if gt(combinedAdditionalRecipients, MaskOverLastTwentyBytes) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, InvalidBasicOrderParameterEncoding_error_selector)
                            // revert(abi.encodeWithSignature(
                            //     "InvalidBasicOrderParameterEncoding()"
                            // ))
                            revert(
                                Error_selector_offset,
                                InvalidBasicOrderParameterEncoding_error_length
                            )
                        }
                    }
                }
                {
                    /**
                     * Next, handle offered items. Memory Layout:
                     *  EIP712 data for OfferItem
                     *   - 0x80:  OfferItem EIP-712 typehash (constant)
                     *   - 0xa0:  itemType
                     *   - 0xc0:  token
                     *   - 0xe0:  identifier (reused for offeredItemsHash)
                     *   - 0x100: startAmount
                     *   - 0x120: endAmount
                     */
                    // Place offer item typehash on the stack.
                    bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
                    // Utilize assembly to enable reuse of memory regions when possible.
                    assembly {
                        /*
                         * 1. Calculate OfferItem EIP712 hash
                         */
                        // Write the OfferItem typeHash to memory.
                        mstore(BasicOrder_offerItem_typeHash_ptr, typeHash)
                        // Write the OfferItem item type to memory.
                        mstore(BasicOrder_offerItem_itemType_ptr, offeredItemType)
                        // Copy calldata region with (offerToken, offerIdentifier,
                        // offerAmount) from OrderParameters to (token, identifier,
                        // startAmount) in OfferItem struct. The offerAmount is written
                        // to startAmount and endAmount as basic orders do not have
                        // dynamic amounts.
                        calldatacopy(
                            BasicOrder_offerItem_token_ptr,
                            BasicOrder_offerToken_cdPtr,
                            ThreeWords
                        )
                        // Copy offerAmount from calldata to endAmount in OfferItem
                        // struct.
                        calldatacopy(
                            BasicOrder_offerItem_endAmount_ptr,
                            BasicOrder_offerAmount_cdPtr,
                            OneWord
                        )
                        // Compute EIP712 OfferItem hash, write result to scratch space:
                        //   `keccak256(abi.encode(offeredItem))`
                        mstore(
                            0,
                            keccak256(
                                BasicOrder_offerItem_typeHash_ptr,
                                EIP712_OfferItem_size
                            )
                        )
                        /*
                         * 2. Calculate hash of array of EIP712 hashes and write the
                         * result to the corresponding OfferItem struct:
                         *   `keccak256(abi.encodePacked(offerItemHashes))`
                         */
                        mstore(BasicOrder_order_offerHashes_ptr, keccak256(0, OneWord))
                    }
                }
                {
                    /**
                     * Once consideration items and offer items have been handled,
                     * derive the final order hash. Memory Layout:
                     *  0x80-0x1c0: EIP712 data for order
                     *   - 0x80:   Order EIP-712 typehash (constant)
                     *   - 0xa0:   orderParameters.offerer
                     *   - 0xc0:   orderParameters.zone
                     *   - 0xe0:   keccak256(abi.encodePacked(offerHashes))
                     *   - 0x100:  keccak256(abi.encodePacked(considerationHashes))
                     *   - 0x120:  orderParameters.basicOrderType (% 4 = orderType)
                     *   - 0x140:  orderParameters.startTime
                     *   - 0x160:  orderParameters.endTime
                     *   - 0x180:  orderParameters.zoneHash
                     *   - 0x1a0:  orderParameters.salt
                     *   - 0x1c0:  orderParameters.conduitKey
                     *   - 0x1e0:  _counters[orderParameters.offerer] (from storage)
                     */
                    // Read the offerer from calldata and place on the stack.
                    address offerer;
                    assembly {
                        offerer := calldataload(BasicOrder_offerer_cdPtr)
                    }
                    // Read offerer's current counter from storage and place on stack.
                    uint256 counter = _getCounter(offerer);
                    // Load order typehash from runtime code and place on stack.
                    bytes32 typeHash = _ORDER_TYPEHASH;
                    assembly {
                        // Set the OrderItem typeHash in memory.
                        mstore(BasicOrder_order_typeHash_ptr, typeHash)
                        // Copy offerer and zone from OrderParameters in calldata to the
                        // Order struct.
                        calldatacopy(
                            BasicOrder_order_offerer_ptr,
                            BasicOrder_offerer_cdPtr,
                            TwoWords
                        )
                        // Copy receivedItemsHash from zero slot to the Order struct.
                        mstore(
                            BasicOrder_order_considerationHashes_ptr,
                            mload(receivedItemsHash_ptr)
                        )
                        // Write the supplied orderType to the Order struct.
                        mstore(BasicOrder_order_orderType_ptr, orderType)
                        // Copy startTime, endTime, zoneHash, salt & conduit from
                        // calldata to the Order struct.
                        calldatacopy(
                            BasicOrder_order_startTime_ptr,
                            BasicOrder_startTime_cdPtr,
                            FiveWords
                        )
                        // Write offerer's counter, retrieved from storage, to struct.
                        mstore(BasicOrder_order_counter_ptr, counter)
                        // Compute the EIP712 Order hash.
                        orderHash := keccak256(
                            BasicOrder_order_typeHash_ptr,
                            EIP712_Order_size
                        )
                    }
                }
                assembly {
                    /**
                     * After the order hash has been derived, emit OrderFulfilled event:
                     *   event OrderFulfilled(
                     *     bytes32 orderHash,
                     *     address indexed offerer,
                     *     address indexed zone,
                     *     address fulfiller,
                     *     SpentItem[] offer,
                     *       > (itemType, token, id, amount)
                     *     ReceivedItem[] consideration
                     *       > (itemType, token, id, amount, recipient)
                     *   )
                     * topic0 - OrderFulfilled event signature
                     * topic1 - offerer
                     * topic2 - zone
                     * data:
                     *  - 0x00: orderHash
                     *  - 0x20: fulfiller
                     *  - 0x40: offer arr ptr (0x80)
                     *  - 0x60: consideration arr ptr (0x120)
                     *  - 0x80: offer arr len (1)
                     *  - 0xa0: offer.itemType
                     *  - 0xc0: offer.token
                     *  - 0xe0: offer.identifier
                     *  - 0x100: offer.amount
                     *  - 0x120: 1 + recipients.length
                     *  - 0x140: recipient 0
                     */
                    // Derive pointer to start of OrderFulfilled event data.
                    let eventDataPtr := add(
                        OrderFulfilled_baseOffset,
                        shl(
                            OneWordShift,
                            calldataload(
                                BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                            )
                        )
                    )
                    // Write the order hash to the head of the event's data region.
                    mstore(eventDataPtr, orderHash)
                    // Write the fulfiller (i.e. the caller) next for receiver argument.
                    mstore(add(eventDataPtr, OrderFulfilled_fulfiller_offset), caller())
                    // Write the SpentItem and ReceivedItem array offsets (constants).
                    mstore(
                        // SpentItem array offset
                        add(eventDataPtr, OrderFulfilled_offer_head_offset),
                        OrderFulfilled_offer_body_offset
                    )
                    mstore(
                        // ReceivedItem array offset
                        add(eventDataPtr, OrderFulfilled_consideration_head_offset),
                        OrderFulfilled_consideration_body_offset
                    )
                    // Set a length of 1 for the offer array.
                    mstore(
                        add(
                            eventDataPtr,
                            OrderFulfilled_offer_length_offset_relativeTo_baseOffset
                        ),
                        1
                    )
                    // Write itemType to the SpentItem struct.
                    mstore(
                        add(
                            eventDataPtr,
                            OrderFulfilled_offer_itemType_offset_relativeTo_baseOffset
                        ),
                        offeredItemType
                    )
                    // Copy calldata region with (offerToken, offerIdentifier,
                    // offerAmount) from OrderParameters to (token, identifier,
                    // amount) in SpentItem struct.
                    calldatacopy(
                        add(
                            eventDataPtr,
                            OrderFulfilled_offer_token_offset_relativeTo_baseOffset
                        ),
                        BasicOrder_offerToken_cdPtr,
                        ThreeWords
                    )
                    // Derive total data size including SpentItem and ReceivedItem data.
                    // SpentItem portion is already included in the baseSize constant,
                    // as there can only be one element in the array.
                    let dataSize := add(
                        OrderFulfilled_baseSize,
                        mul(
                            calldataload(BasicOrder_addlRecipients_length_cdPtr),
                            ReceivedItem_size
                        )
                    )
                    // Emit OrderFulfilled log with three topics (the event signature
                    // as well as the two indexed arguments, the offerer and the zone).
                    log3(
                        // Supply the pointer for event data in memory.
                        eventDataPtr,
                        // Supply the size of event data in memory.
                        dataSize,
                        // Supply the OrderFulfilled event signature.
                        OrderFulfilled_selector,
                        // Supply the first topic (the offerer).
                        calldataload(BasicOrder_offerer_cdPtr),
                        // Supply the second topic (the zone).
                        calldataload(BasicOrder_zone_cdPtr)
                    )
                    // Restore the zero slot.
                    mstore(ZeroSlot, 0)
                    // Update the free memory pointer so that event data is persisted.
                    mstore(
                        FreeMemoryPointerSlot,
                        add(
                            eventDataPtr,
                            // Reserve extra 3 words to be used by `authorizeOrder` and
                            // `validatateOrder` if pre-post exection hook to the zone
                            // is required. These 3 memory slots will be used for the
                            // extra data/context and order hashes of the calldata.
                            add(
                                dataSize,
                                OrderFulfilled_post_memory_region_reservedBytes
                            )
                        )
                    )
                }
                // Verify the status of the derived order.
                OrderStatus storage orderStatus = _validateBasicOrder(orderHash);
                // Determine whether order is restricted and, if so, that it is valid.
                callDataPointer = _assertRestrictedBasicOrderAuthorization(
                    orderHash,
                    orderType
                );
                // Update the status of the order and mark as fully filled.
                _updateBasicOrderStatus(orderStatus);
                // Return the derived order hash.
                return (orderHash, callDataPointer);
            }
            /**
             * @dev Internal function to transfer an individual ERC721 or ERC1155 item
             *      from a given originator to a given recipient. The accumulator will
             *      be bypassed, meaning that this function should be utilized in cases
             *      where multiple item transfers can be accumulated into a single
             *      conduit call. Sufficient approvals must be set, either on the
             *      respective conduit or on this contract. Note that this function may
             *      only be safely called as part of basic orders, as it assumes a
             *      specific calldata encoding structure that must first be validated.
             *
             * @param itemType   The type of item to transfer, either ERC721 or ERC1155.
             * @param conduitKey A bytes32 value indicating what corresponding conduit,
             *                   if any, to source token approvals from. The zero hash
             *                   signifies that no conduit should be used, with direct
             *                   approvals set on this contract.
             */
            function _transferIndividual721Or1155Item(
                ItemType itemType,
                bytes32 conduitKey
            ) internal {
                // Retrieve token, from, identifier, and amount from calldata using
                // fixed calldata offsets based on strict basic parameter encoding.
                address token;
                address from;
                uint256 identifier;
                uint256 amount;
                assembly {
                    token := calldataload(BasicOrder_offerToken_cdPtr)
                    from := calldataload(BasicOrder_offerer_cdPtr)
                    identifier := calldataload(BasicOrder_offerIdentifier_cdPtr)
                    amount := calldataload(BasicOrder_offerAmount_cdPtr)
                }
                // Determine if the transfer is to be performed via a conduit.
                if (conduitKey != bytes32(0)) {
                    // Ensure that the amount is non-zero.
                    _assertNonZeroAmount(amount);
                    // Use free memory pointer as calldata offset for the conduit call.
                    uint256 callDataOffset;
                    // Utilize assembly to place each argument in free memory.
                    assembly {
                        // Retrieve the free memory pointer and use it as the offset.
                        callDataOffset := mload(FreeMemoryPointerSlot)
                        // Write ConduitInterface.execute.selector to memory.
                        mstore(callDataOffset, Conduit_execute_signature)
                        // Write the offset to the ConduitTransfer array in memory.
                        mstore(
                            add(
                                callDataOffset,
                                Conduit_execute_ConduitTransfer_offset_ptr
                            ),
                            Conduit_execute_ConduitTransfer_ptr
                        )
                        // Write the length of the ConduitTransfer array to memory.
                        mstore(
                            add(
                                callDataOffset,
                                Conduit_execute_ConduitTransfer_length_ptr
                            ),
                            Conduit_execute_ConduitTransfer_length
                        )
                        // Write the item type to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferItemType_ptr),
                            itemType
                        )
                        // Write the token to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferToken_ptr),
                            token
                        )
                        // Write the transfer source to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferFrom_ptr),
                            from
                        )
                        // Write the transfer recipient (the caller) to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferTo_ptr),
                            caller()
                        )
                        // Write the token identifier to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferIdentifier_ptr),
                            identifier
                        )
                        // Write the transfer amount to memory.
                        mstore(
                            add(callDataOffset, Conduit_execute_transferAmount_ptr),
                            amount
                        )
                    }
                    // Perform the call to the conduit.
                    _callConduitUsingOffsets(
                        conduitKey,
                        callDataOffset,
                        OneConduitExecute_size
                    );
                } else {
                    // Otherwise, determine whether it is an ERC721 or ERC1155 item.
                    if (itemType == ItemType.ERC721) {
                        // Ensure that exactly one 721 item is being transferred.
                        if (amount != 1) {
                            _revertInvalidERC721TransferAmount(amount);
                        }
                        // Perform transfer to caller via the token contract directly.
                        _performERC721Transfer(token, from, msg.sender, identifier);
                    } else {
                        // Ensure that the amount is non-zero.
                        _assertNonZeroAmount(amount);
                        // Perform transfer to caller via the token contract directly.
                        _performERC1155Transfer(
                            token,
                            from,
                            msg.sender,
                            identifier,
                            amount
                        );
                    }
                }
            }
            /**
             * @dev Internal function to transfer Ether (or other native tokens) to a
             *      given recipient as part of basic order fulfillment. Note that
             *      conduits are not utilized for native tokens as the transferred
             *      amount must be provided as msg.value. Also note that this function
             *      may only be safely called as part of basic orders, as it assumes a
             *      specific calldata encoding structure that must first be validated.
             */
            function _transferNativeTokensAndFinalize() internal {
                // Put native token value supplied by the caller on the stack.
                uint256 nativeTokensRemaining = msg.value;
                // Retrieve consideration amount, offerer, and total size of additional
                // recipients data from calldata using fixed offsets and place on stack.
                uint256 amount;
                address payable to;
                uint256 totalAdditionalRecipientsDataSize;
                assembly {
                    amount := calldataload(BasicOrder_considerationAmount_cdPtr)
                    to := calldataload(BasicOrder_offerer_cdPtr)
                    totalAdditionalRecipientsDataSize := shl(
                        AdditionalRecipient_size_shift,
                        calldataload(BasicOrder_addlRecipients_length_cdPtr)
                    )
                }
                uint256 additionalRecipientAmount;
                address payable recipient;
                // Skip overflow check as for loop is indexed starting at zero.
                unchecked {
                    // Iterate over additional recipient data by two-word element.
                    for (
                        uint256 i = 0;
                        i < totalAdditionalRecipientsDataSize;
                        i += AdditionalRecipient_size
                    ) {
                        assembly {
                            // Retrieve calldata pointer for additional recipient.
                            let additionalRecipientCdPtr := add(
                                BasicOrder_additionalRecipients_data_cdPtr,
                                i
                            )
                            additionalRecipientAmount := calldataload(
                                additionalRecipientCdPtr
                            )
                            recipient := calldataload(
                                add(OneWord, additionalRecipientCdPtr)
                            )
                        }
                        // Ensure that sufficient native tokens are available.
                        if (additionalRecipientAmount > nativeTokensRemaining) {
                            _revertInsufficientNativeTokensSupplied();
                        }
                        // Reduce native token value available. Skip underflow check as
                        // subtracted value is confirmed above as less than remaining.
                        nativeTokensRemaining -= additionalRecipientAmount;
                        // Transfer native tokens to the additional recipient.
                        _transferNativeTokens(recipient, additionalRecipientAmount);
                    }
                }
                // Ensure that sufficient native tokens are still available.
                if (amount > nativeTokensRemaining) {
                    _revertInsufficientNativeTokensSupplied();
                }
                // Transfer native tokens to the offerer.
                _transferNativeTokens(to, amount);
                // If any native tokens remain after transfers, return to the caller.
                if (nativeTokensRemaining > amount) {
                    // Skip underflow check as nativeTokensRemaining > amount.
                    unchecked {
                        // Transfer remaining native tokens to the caller.
                        _transferNativeTokens(
                            payable(msg.sender),
                            nativeTokensRemaining - amount
                        );
                    }
                }
            }
            /**
             * @dev Internal function to transfer ERC20 tokens to a given recipient as
             *      part of basic order fulfillment. Note that this function may only be
             *      safely called as part of basic orders, as it assumes a specific
             *      calldata encoding structure that must first be validated. Also note
             *      that basic order parameters are retrieved using fixed offsets, this
             *      requires that strict basic order encoding has already been verified.
             *
             * @param fromOfferer A boolean indicating whether to decrement amount from
             *                    the offered amount.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _transferERC20AndFinalize(
                bool fromOfferer,
                bytes memory accumulator
            ) internal {
                // Declare from and to variables determined by fromOfferer value.
                address from;
                address to;
                // Declare token and amount variables determined by fromOfferer value.
                address token;
                uint256 amount;
                // Declare and check identifier variable within an isolated scope.
                {
                    // Declare identifier variable determined by fromOfferer value.
                    uint256 identifier;
                    // Set ERC20 token transfer variables based on fromOfferer boolean.
                    if (fromOfferer) {
                        // Use offerer as from value, msg.sender as to value, and offer
                        // token, identifier, & amount values if token is from offerer.
                        assembly {
                            from := calldataload(BasicOrder_offerer_cdPtr)
                            to := caller()
                            token := calldataload(BasicOrder_offerToken_cdPtr)
                            identifier := calldataload(BasicOrder_offerIdentifier_cdPtr)
                            amount := calldataload(BasicOrder_offerAmount_cdPtr)
                        }
                    } else {
                        // Otherwise, use msg.sender as from value, offerer as to value,
                        // and consideration token, identifier, and amount values.
                        assembly {
                            from := caller()
                            to := calldataload(BasicOrder_offerer_cdPtr)
                            token := calldataload(BasicOrder_considerationToken_cdPtr)
                            identifier := calldataload(
                                BasicOrder_considerationIdentifier_cdPtr
                            )
                            amount := calldataload(BasicOrder_considerationAmount_cdPtr)
                        }
                    }
                    // Ensure that no identifier is supplied.
                    if (identifier != 0) {
                        _revertUnusedItemParameters();
                    }
                }
                // Determine the appropriate conduit to utilize.
                bytes32 conduitKey;
                // Utilize assembly to derive conduit (if relevant) based on route.
                assembly {
                    // Use offerer conduit if fromOfferer, fulfiller conduit otherwise.
                    conduitKey := calldataload(
                        sub(
                            BasicOrder_fulfillerConduit_cdPtr,
                            shl(OneWordShift, fromOfferer)
                        )
                    )
                }
                // Retrieve total size of additional recipients data and place on stack.
                uint256 totalAdditionalRecipientsDataSize;
                assembly {
                    totalAdditionalRecipientsDataSize := shl(
                        AdditionalRecipient_size_shift,
                        calldataload(BasicOrder_addlRecipients_length_cdPtr)
                    )
                }
                uint256 additionalRecipientAmount;
                address recipient;
                // Iterate over each additional recipient.
                for (uint256 i = 0; i < totalAdditionalRecipientsDataSize; ) {
                    assembly {
                        // Retrieve calldata pointer for additional recipient.
                        let additionalRecipientCdPtr := add(
                            BasicOrder_additionalRecipients_data_cdPtr,
                            i
                        )
                        additionalRecipientAmount := calldataload(
                            additionalRecipientCdPtr
                        )
                        recipient := calldataload(
                            add(OneWord, additionalRecipientCdPtr)
                        )
                    }
                    // Decrement the amount to transfer to fulfiller if indicated.
                    if (fromOfferer) {
                        amount -= additionalRecipientAmount;
                    }
                    // Transfer ERC20 tokens to additional recipient given approval.
                    _transferERC20(
                        token,
                        from,
                        recipient,
                        additionalRecipientAmount,
                        conduitKey,
                        accumulator
                    );
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        i += AdditionalRecipient_size;
                    }
                }
                // Transfer ERC20 token amount (from account must have proper approval).
                _transferERC20(token, from, to, amount, conduitKey, accumulator);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ItemType,
            OrderType,
            Side
        } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            ConsiderationItem,
            CriteriaResolver,
            MemoryPointer,
            OfferItem,
            OrderParameters
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            _revertCriteriaNotEnabledForItem,
            _revertInvalidProof,
            _revertOrderCriteriaResolverOutOfRange
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            CriteriaResolutionErrors
        } from "seaport-types/src/interfaces/CriteriaResolutionErrors.sol";
        import {
            OneWord,
            OneWordShift,
            OrderParameters_consideration_head_offset,
            Selector_length,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            ConsiderationCriteriaResolverOutOfRange_err_selector,
            Error_selector_offset,
            OfferCriteriaResolverOutOfRange_error_selector,
            UnresolvedConsiderationCriteria_error_itemIndex_ptr,
            UnresolvedConsiderationCriteria_error_length,
            UnresolvedConsiderationCriteria_error_orderIndex_ptr,
            UnresolvedConsiderationCriteria_error_selector,
            UnresolvedOfferCriteria_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title CriteriaResolution
         * @author 0age
         * @notice CriteriaResolution contains a collection of pure functions related to
         *         resolving criteria-based items.
         */
        contract CriteriaResolution is CriteriaResolutionErrors {
            /**
             * @dev Internal pure function to apply criteria resolvers containing
             *      specific token identifiers and associated proofs to order items.
             *
             * @param advancedOrders     The orders to apply criteria resolvers to.
             * @param criteriaResolvers  An array where each element contains a
             *                           reference to a specific order as well as that
             *                           order's offer or consideration, a token
             *                           identifier, and a proof that the supplied token
             *                           identifier is contained in the order's merkle
             *                           root. Note that a root of zero indicates that
             *                           any transferable token identifier is valid and
             *                           that no proof needs to be supplied.
             */
            function _applyCriteriaResolvers(
                AdvancedOrder[] memory advancedOrders,
                CriteriaResolver[] memory criteriaResolvers
            ) internal pure {
                // Skip overflow checks as all for loops are indexed starting at zero.
                unchecked {
                    // Retrieve length of criteria resolvers array and place on stack.
                    uint256 totalCriteriaResolvers = criteriaResolvers.length;
                    // Retrieve length of orders array and place on stack.
                    uint256 totalAdvancedOrders = advancedOrders.length;
                    // Iterate over each criteria resolver.
                    for (uint256 i = 0; i < totalCriteriaResolvers; ++i) {
                        // Retrieve the criteria resolver.
                        CriteriaResolver memory criteriaResolver = (
                            criteriaResolvers[i]
                        );
                        // Read the order index from memory and place it on the stack.
                        uint256 orderIndex = criteriaResolver.orderIndex;
                        // Ensure that the order index is in range.
                        if (orderIndex >= totalAdvancedOrders) {
                            _revertOrderCriteriaResolverOutOfRange(
                                criteriaResolver.side
                            );
                        }
                        // Retrieve the referenced advanced order.
                        AdvancedOrder memory advancedOrder = advancedOrders[orderIndex];
                        // Skip criteria resolution for order if not fulfilled.
                        if (advancedOrder.numerator == 0) {
                            continue;
                        }
                        // Retrieve the parameters for the order.
                        OrderParameters memory orderParameters = (
                            advancedOrder.parameters
                        );
                        {
                            // Get a pointer to the list of items to give to
                            // _updateCriteriaItem. If the resolver refers to a
                            // consideration item, this array pointer will be replaced
                            // with the consideration array.
                            OfferItem[] memory items = orderParameters.offer;
                            // Read component index from memory and place it on stack.
                            uint256 componentIndex = criteriaResolver.index;
                            // Get error selector for `OfferCriteriaResolverOutOfRange`.
                            uint256 errorSelector = (
                                OfferCriteriaResolverOutOfRange_error_selector
                            );
                            // If the resolver refers to a consideration item...
                            if (criteriaResolver.side != Side.OFFER) {
                                // Get the pointer to `orderParameters.consideration`
                                // Using the array directly has a significant impact on
                                // the optimized compiler output.
                                MemoryPointer considerationPtr = orderParameters
                                    .toMemoryPointer()
                                    .pptrOffset(
                                        OrderParameters_consideration_head_offset
                                    );
                                // Replace the items pointer with a pointer to the
                                // consideration array.
                                assembly {
                                    items := considerationPtr
                                }
                                // Replace the error selector with the selector for
                                // `ConsiderationCriteriaResolverOutOfRange`.
                                errorSelector = (
                                    ConsiderationCriteriaResolverOutOfRange_err_selector
                                );
                            }
                            // Ensure that the component index is in range.
                            if (componentIndex >= items.length) {
                                assembly {
                                    // Revert with either
                                    // `OfferCriteriaResolverOutOfRange()` or
                                    // `ConsiderationCriteriaResolverOutOfRange()`,
                                    // depending on whether the resolver refers to a
                                    // consideration item.
                                    mstore(0, errorSelector)
                                    // revert(abi.encodeWithSignature(
                                    //    "OfferCriteriaResolverOutOfRange()"
                                    // ))
                                    // or
                                    // revert(abi.encodeWithSignature(
                                    //    "ConsiderationCriteriaResolverOutOfRange()"
                                    // ))
                                    revert(Error_selector_offset, Selector_length)
                                }
                            }
                            // Apply the criteria resolver to the item in question.
                            _updateCriteriaItem(
                                items,
                                componentIndex,
                                criteriaResolver
                            );
                        }
                    }
                    // Iterate over each advanced order.
                    for (uint256 i = 0; i < totalAdvancedOrders; ++i) {
                        // Retrieve the advanced order.
                        AdvancedOrder memory advancedOrder = advancedOrders[i];
                        // Skip criteria resolution for order if not fulfilled.
                        if (advancedOrder.numerator == 0) {
                            continue;
                        }
                        // Retrieve the parameters for the order.
                        OrderParameters memory orderParameters = (
                            advancedOrder.parameters
                        );
                        OrderType orderType = orderParameters.orderType;
                        _ensureAllRequiredCriteriaResolved(
                            i,
                            orderParameters.consideration,
                            orderType,
                            UnresolvedConsiderationCriteria_error_selector
                        );
                        _toOfferItemArgumentType(_ensureAllRequiredCriteriaResolved)(
                            i,
                            orderParameters.offer,
                            orderType,
                            UnresolvedOfferCriteria_error_selector
                        );
                    }
                }
            }
            /**
             * @dev Internal pure function to examine an array of items and ensure that
             *      all criteria-based items (with the exception of wildcard items on
             *      contract orders) have had a criteria resolver successfully applied.
             *
             * @param orderIndex     The index of the order being examined.
             * @param items          The items to examine. These are consideration items
             *                       in the default case, but offer items are also
             *                       casted to consideration items as required.
             * @param orderType      The type of order being examined.
             * @param revertSelector The selector to use when reverting.
             */
            function _ensureAllRequiredCriteriaResolved(
                uint256 orderIndex,
                ConsiderationItem[] memory items,
                OrderType orderType,
                uint256 revertSelector
            ) internal pure {
                // Read items array length from memory and place on stack.
                uint256 totalItems = items.length;
                // Iterate over each item on the order.
                for (uint256 i = 0; i < totalItems; ++i) {
                    ConsiderationItem memory item = items[i];
                    // Revert if the item is still a criteria item unless the
                    // order is a contract order and the identifier is 0.
                    ItemType itemType = item.itemType;
                    uint256 identifierOrCriteria = item.identifierOrCriteria;
                    assembly {
                        if and(
                            gt(itemType, 3), // Criteria-based item
                            or(
                                iszero(eq(orderType, 4)), // not OrderType.CONTRACT
                                iszero(iszero(identifierOrCriteria)) // not wildcard
                            )
                        ) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, revertSelector)
                            // Store arguments.
                            mstore(
                                UnresolvedConsiderationCriteria_error_orderIndex_ptr,
                                orderIndex
                            )
                            mstore(
                                UnresolvedConsiderationCriteria_error_itemIndex_ptr,
                                i
                            )
                            // Revert with appropriate UnresolvedCriteria error message.
                            // Unresolved[Offer|Consideration]Criteria(uint256, uint256)
                            revert(
                                Error_selector_offset,
                                UnresolvedConsiderationCriteria_error_length
                            )
                        }
                    }
                }
            }
            /**
             * @dev Internal pure function to perform a function cast from a function
             *      that accepts consideration items to a function that accepts offer
             *      items, used by _ensureAllRequiredCriteriaResolved to ensure that
             *      all necessary criteria items have been resolved for an order.
             *
             * @param inFn  The function that accepts consideration items.
             * @param outFn The function that accepts offer items.
             */
            function _toOfferItemArgumentType(
                function(uint256, ConsiderationItem[] memory, OrderType, uint256)
                    internal
                    pure inFn
            )
                internal
                pure
                returns (
                    function(uint256, OfferItem[] memory, OrderType, uint256)
                        internal
                        pure outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Internal pure function to update a criteria item.
             *
             * @param offer             The offer containing the item to update.
             * @param componentIndex    The index of the item to update.
             * @param criteriaResolver  The criteria resolver to use to update the item.
             */
            function _updateCriteriaItem(
                OfferItem[] memory offer,
                uint256 componentIndex,
                CriteriaResolver memory criteriaResolver
            ) internal pure {
                // Retrieve relevant item using the component index.
                OfferItem memory offerItem = offer[componentIndex];
                // Read item type and criteria from memory & place on stack.
                ItemType itemType = offerItem.itemType;
                // Ensure the specified item type indicates criteria usage.
                if (!_isItemWithCriteria(itemType)) {
                    _revertCriteriaNotEnabledForItem();
                }
                uint256 identifierOrCriteria = offerItem.identifierOrCriteria;
                // If criteria is not 0 (i.e. a collection-wide criteria-based item)...
                if (identifierOrCriteria != uint256(0)) {
                    // Verify identifier inclusion in criteria root using proof.
                    _verifyProof(
                        criteriaResolver.identifier,
                        identifierOrCriteria,
                        criteriaResolver.criteriaProof
                    );
                } else if (criteriaResolver.criteriaProof.length != 0) {
                    // Revert if non-empty proof is supplied for a collection-wide item.
                    _revertInvalidProof();
                }
                // Update item type to remove criteria usage.
                // Use assembly to operate on ItemType enum as a number.
                ItemType newItemType;
                assembly {
                    // Item type 4 becomes 2 and item type 5 becomes 3.
                    newItemType := sub(itemType, 2)
                }
                offerItem.itemType = newItemType;
                // Update identifier w/ supplied identifier.
                offerItem.identifierOrCriteria = criteriaResolver.identifier;
            }
            /**
             * @dev Internal pure function to check whether a given item type represents
             *      a criteria-based ERC721 or ERC1155 item (e.g. an item that can be
             *      resolved to one of a number of different identifiers at the time of
             *      order fulfillment).
             *
             * @param itemType The item type in question.
             *
             * @return withCriteria A boolean indicating that the item type in question
             *                      represents a criteria-based item.
             */
            function _isItemWithCriteria(
                ItemType itemType
            ) internal pure returns (bool withCriteria) {
                // ERC721WithCriteria is ItemType 4. ERC1155WithCriteria is ItemType 5.
                assembly {
                    withCriteria := gt(itemType, 3)
                }
            }
            /**
             * @dev Internal pure function to ensure that a given element is contained
             *      in a merkle root via a supplied proof.
             *
             * @param leaf  The element for which to prove inclusion.
             * @param root  The merkle root that inclusion will be proved against.
             * @param proof The merkle proof.
             */
            function _verifyProof(
                uint256 leaf,
                uint256 root,
                bytes32[] memory proof
            ) internal pure {
                // Declare a variable that will be used to determine proof validity.
                bool isValid;
                // Utilize assembly to efficiently verify the proof against the root.
                assembly {
                    // Store the leaf at the beginning of scratch space.
                    mstore(0, leaf)
                    // Derive the hash of the leaf to use as the initial proof element.
                    let computedHash := keccak256(0, OneWord)
                    // Get memory start location of the first element in proof array.
                    let data := add(proof, OneWord)
                    // Iterate over each proof element to compute the root hash.
                    for {
                        // Left shift by 5 is equivalent to multiplying by 0x20.
                        let end := add(data, shl(OneWordShift, mload(proof)))
                    } lt(data, end) {
                        // Increment by one word at a time.
                        data := add(data, OneWord)
                    } {
                        // Get the proof element.
                        let loadedData := mload(data)
                        // Sort proof elements and place them in scratch space.
                        // Slot of `computedHash` in scratch space.
                        // If the condition is true: 0x20, otherwise: 0x00.
                        let scratch := shl(OneWordShift, gt(computedHash, loadedData))
                        // Store elements to hash contiguously in scratch space. Scratch
                        // space is 64 bytes (0x00 - 0x3f) & both elements are 32 bytes.
                        mstore(scratch, computedHash)
                        mstore(xor(scratch, OneWord), loadedData)
                        // Derive the updated hash.
                        computedHash := keccak256(0, TwoWords)
                    }
                    // Compare the final hash to the supplied root.
                    isValid := eq(computedHash, root)
                }
                // Revert if computed hash does not equal supplied root.
                if (!isValid) {
                    _revertInvalidProof();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            AmountDerivationErrors
        } from "seaport-types/src/interfaces/AmountDerivationErrors.sol";
        import {
            Error_selector_offset,
            InexactFraction_error_length,
            InexactFraction_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title AmountDeriver
         * @author 0age
         * @notice AmountDeriver contains view and pure functions related to deriving
         *         item amounts based on partial fill quantity and on linear
         *         interpolation based on current time when the start amount and end
         *         amount differ.
         */
        contract AmountDeriver is AmountDerivationErrors {
            /**
             * @dev Internal view function to derive the current amount of a given item
             *      based on the current price, the starting price, and the ending
             *      price. If the start and end prices differ, the current price will be
             *      interpolated on a linear basis. Note that this function expects that
             *      the startTime parameter of orderParameters is not greater than the
             *      current block timestamp and that the endTime parameter is greater
             *      than the current block timestamp. If this condition is not upheld,
             *      duration / elapsed / remaining variables will underflow.
             *
             * @param startAmount The starting amount of the item.
             * @param endAmount   The ending amount of the item.
             * @param startTime   The starting time of the order.
             * @param endTime     The end time of the order.
             * @param roundUp     A boolean indicating whether the resultant amount
             *                    should be rounded up or down.
             *
             * @return amount The current amount.
             */
            function _locateCurrentAmount(
                uint256 startAmount,
                uint256 endAmount,
                uint256 startTime,
                uint256 endTime,
                bool roundUp
            ) internal view returns (uint256 amount) {
                // Only modify end amount if it doesn't already equal start amount.
                if (startAmount != endAmount) {
                    // Declare variables to derive in the subsequent unchecked scope.
                    uint256 duration;
                    uint256 elapsed;
                    uint256 remaining;
                    // Skip underflow checks as startTime <= block.timestamp < endTime.
                    unchecked {
                        // Derive the duration for the order and place it on the stack.
                        duration = endTime - startTime;
                        // Derive time elapsed since the order started & place on stack.
                        elapsed = block.timestamp - startTime;
                        // Derive time remaining until order expires and place on stack.
                        remaining = duration - elapsed;
                    }
                    // Aggregate new amounts weighted by time with rounding factor.
                    uint256 totalBeforeDivision = ((startAmount * remaining) +
                        (endAmount * elapsed));
                    // Use assembly to combine operations and skip divide-by-zero check.
                    assembly {
                        // Multiply by iszero(iszero(totalBeforeDivision)) to ensure
                        // amount is set to zero if totalBeforeDivision is zero,
                        // as intermediate overflow can occur if it is zero.
                        amount := mul(
                            iszero(iszero(totalBeforeDivision)),
                            // Subtract 1 from the numerator and add 1 to the result
                            // if roundUp is true to get proper rounding direction.
                            // Division is performed with no zero check as duration
                            // cannot be zero as long as startTime < endTime.
                            add(
                                div(sub(totalBeforeDivision, roundUp), duration),
                                roundUp
                            )
                        )
                    }
                    // Return the current amount.
                    return amount;
                }
                // Return the original amount as startAmount == endAmount.
                return endAmount;
            }
            /**
             * @dev Internal pure function to return a fraction of a given value and to
             *      ensure the resultant value does not have any fractional component.
             *      Note that this function assumes that zero will never be supplied as
             *      the denominator parameter; invalid / undefined behavior will result
             *      should a denominator of zero be provided.
             *
             * @param numerator   A value indicating the portion of the order that
             *                    should be filled.
             * @param denominator A value indicating the total size of the order. Note
             *                    that this value cannot be equal to zero.
             * @param value       The value for which to compute the fraction.
             *
             * @return newValue The value after applying the fraction.
             */
            function _getFraction(
                uint256 numerator,
                uint256 denominator,
                uint256 value
            ) internal pure returns (uint256 newValue) {
                // Return value early in cases where the fraction resolves to 1.
                if (numerator == denominator) {
                    return value;
                }
                // Ensure fraction can be applied to the value with no remainder. Note
                // that the denominator cannot be zero.
                assembly {
                    // Ensure new value contains no remainder via mulmod operator.
                    // Credit to @hrkrshnn + @axic for proposing this optimal solution.
                    if mulmod(value, numerator, denominator) {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, InexactFraction_error_selector)
                        // revert(abi.encodeWithSignature("InexactFraction()"))
                        revert(Error_selector_offset, InexactFraction_error_length)
                    }
                }
                // Multiply the numerator by the value and ensure no overflow occurs.
                uint256 valueTimesNumerator = value * numerator;
                // Divide by the denominator (note that denominator cannot be zero).
                assembly {
                    // Perform division without zero check.
                    newValue := div(valueTimesNumerator, denominator)
                }
            }
            /**
             * @dev Internal view function to apply a fraction to a consideration
             * or offer item.
             *
             * @param startAmount     The starting amount of the item.
             * @param endAmount       The ending amount of the item.
             * @param numerator       A value indicating the portion of the order that
             *                        should be filled.
             * @param denominator     A value indicating the total size of the order.
             * @param startTime       The starting time of the order.
             * @param endTime         The end time of the order.
             * @param roundUp         A boolean indicating whether the resultant
             *                        amount should be rounded up or down.
             *
             * @return amount The received item to transfer with the final amount.
             */
            function _applyFraction(
                uint256 startAmount,
                uint256 endAmount,
                uint256 numerator,
                uint256 denominator,
                uint256 startTime,
                uint256 endTime,
                bool roundUp
            ) internal view returns (uint256 amount) {
                // If start amount equals end amount, apply fraction to end amount.
                if (startAmount == endAmount) {
                    // Apply fraction to end amount.
                    amount = _getFraction(numerator, denominator, endAmount);
                } else {
                    // Otherwise, apply fraction to both and interpolated final amount.
                    amount = _locateCurrentAmount(
                        _getFraction(numerator, denominator, startAmount),
                        _getFraction(numerator, denominator, endAmount),
                        startTime,
                        endTime,
                        roundUp
                    );
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import { Side } from "../lib/ConsiderationEnums.sol";
        /**
         * @title FulfillmentApplicationErrors
         * @author 0age
         * @notice FulfillmentApplicationErrors contains errors related to fulfillment
         *         application and aggregation.
         */
        interface FulfillmentApplicationErrors {
            /**
             * @dev Revert with an error when a fulfillment is provided that does not
             *      declare at least one component as part of a call to fulfill
             *      available orders.
             */
            error MissingFulfillmentComponentOnAggregation(Side side);
            /**
             * @dev Revert with an error when a fulfillment is provided that does not
             *      declare at least one offer component and at least one consideration
             *      component.
             */
            error OfferAndConsiderationRequiredOnFulfillment();
            /**
             * @dev Revert with an error when the initial offer item named by a
             *      fulfillment component does not match the type, token, identifier,
             *      or conduit preference of the initial consideration item.
             *
             * @param fulfillmentIndex The index of the fulfillment component that
             *                         does not match the initial offer item.
             */
            error MismatchedFulfillmentOfferAndConsiderationComponents(
                uint256 fulfillmentIndex
            );
            /**
             * @dev Revert with an error when an order or item index are out of range
             *      or a fulfillment component does not match the type, token,
             *      identifier, or conduit preference of the initial consideration item.
             */
            error InvalidFulfillmentComponentData();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import { OrderType } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            ConsiderationItem,
            OfferItem,
            Order,
            OrderComponents,
            OrderParameters,
            OrderStatus
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            _revertBadFraction,
            _revertCannotCancelOrder,
            _revertConsiderationLengthNotEqualToTotalOriginal,
            _revertInvalidContractOrder,
            _revertPartialFillsNotEnabledForOrder
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import { Executor } from "./Executor.sol";
        import { ZoneInteraction } from "./ZoneInteraction.sol";
        import { MemoryPointer } from "seaport-types/src/helpers/PointerLibraries.sol";
        import {
            AdvancedOrder_denominator_offset,
            AdvancedOrder_numerator_offset,
            BasicOrder_basicOrderParameters_cd_offset,
            BasicOrder_offerer_cdPtr,
            BasicOrder_signature_cdPtr,
            Common_amount_offset,
            Common_endAmount_offset,
            Common_identifier_offset,
            Common_token_offset,
            ConsiderItem_recipient_offset,
            ContractOrder_orderHash_offerer_shift,
            MaxUint120,
            OrderStatus_filledDenominator_offset,
            OrderStatus_filledNumerator_offset,
            OrderStatus_ValidatedAndNotCancelled,
            OrderStatus_ValidatedAndNotCancelledAndFullyFilled,
            ReceivedItem_recipient_offset
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            Panic_arithmetic,
            Panic_error_code_ptr,
            Panic_error_length,
            Panic_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        import {
            CalldataPointer
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        /**
         * @title OrderValidator
         * @author 0age
         * @notice OrderValidator contains functionality related to validating orders
         *         and updating their status.
         */
        contract OrderValidator is Executor, ZoneInteraction {
            // Track status of each order (validated, cancelled, and fraction filled).
            mapping(bytes32 => OrderStatus) private _orderStatus;
            // Track nonces for contract offerers.
            mapping(address => uint256) internal _contractNonces;
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) Executor(conduitController) {}
            /**
             * @dev Internal function to verify the status of a basic order.
             *      Note that this function may only be safely called as part of basic
             *      orders, as it assumes a specific calldata encoding structure that
             *      must first be validated.
             *
             * @param orderHash The hash of the order.
             */
            function _validateBasicOrder(
                bytes32 orderHash
            ) internal view returns (OrderStatus storage orderStatus) {
                // Retrieve offerer directly using fixed calldata offset based on strict
                // basic parameter encoding.
                address offerer;
                assembly {
                    offerer := calldataload(BasicOrder_offerer_cdPtr)
                }
                // Retrieve the order status for the given order hash.
                orderStatus = _orderStatus[orderHash];
                // Ensure order is fillable and is not cancelled.
                _verifyOrderStatus(
                    orderHash,
                    orderStatus,
                    true, // Only allow unused orders when fulfilling basic orders.
                    _runTimeConstantTrue() // Signifies to revert if order is invalid.
                );
                unchecked {
                    // If the order is not already validated, verify supplied signature.
                    if (!orderStatus.isValidated) {
                        _verifySignature(
                            offerer,
                            orderHash,
                            _toBytesReturnType(_decodeBytes)(
                                // Wrap the absolute pointer to the order signature as a
                                // CalldataPointer.
                                CalldataPointer.wrap(
                                    // Read the relative pointer to the order signature.
                                    CalldataPointer
                                        .wrap(BasicOrder_signature_cdPtr)
                                        .readMaskedUint256() +
                                        // Add the BasicOrderParameters struct offset to
                                        // the relative pointer.
                                        BasicOrder_basicOrderParameters_cd_offset
                                )
                            )
                        );
                    }
                }
            }
            /**
             * @dev Internal function to update the status of a basic order, assuming
             *      all validation has already been performed.
             *
             * @param orderStatus A storage pointer referencing the order status.
             */
            function _updateBasicOrderStatus(OrderStatus storage orderStatus) internal {
                // Utilize assembly to efficiently update the order status.
                assembly {
                    // Update order status as validated, not cancelled, & fully filled.
                    sstore(
                        orderStatus.slot,
                        OrderStatus_ValidatedAndNotCancelledAndFullyFilled
                    )
                }
            }
            /**
             * @dev Internal function to validate an order, determine what portion to
             *      fill, and update its status. The desired fill amount is supplied as
             *      a fraction, as is the returned amount to fill.
             *
             * @param advancedOrder     The order to fulfill as well as the fraction to
             *                          fill. Note that all offer and consideration
             *                          amounts must divide with no remainder in order
             *                          for a partial fill to be valid.
             * @param revertOnInvalid   A boolean indicating whether to revert if the
             *                          order is invalid due to the time or status.
             *
             * @return orderHash      The order hash.
             * @return numerator      A value indicating the portion of the order that
             *                        will be filled.
             * @return denominator    A value indicating the total size of the order.
             */
            function _validateOrder(
                AdvancedOrder memory advancedOrder,
                bool revertOnInvalid
            )
                internal
                view
                returns (bytes32 orderHash, uint256 numerator, uint256 denominator)
            {
                // Retrieve the parameters for the order.
                OrderParameters memory orderParameters = advancedOrder.parameters;
                // Ensure current timestamp falls between order start time and end time.
                if (
                    !_verifyTime(
                        orderParameters.startTime,
                        orderParameters.endTime,
                        revertOnInvalid
                    )
                ) {
                    // Assuming an invalid time and no revert, return zeroed out values.
                    return (bytes32(0), 0, 0);
                }
                // Read numerator and denominator from memory and place on the stack.
                // Note that overflowed values are masked.
                assembly {
                    numerator := and(
                        mload(add(advancedOrder, AdvancedOrder_numerator_offset)),
                        MaxUint120
                    )
                    denominator := and(
                        mload(add(advancedOrder, AdvancedOrder_denominator_offset)),
                        MaxUint120
                    )
                }
                // Declare variable for tracking the validity of the supplied fraction.
                bool invalidFraction;
                // If the order is a contract order, return the generated order.
                if (orderParameters.orderType == OrderType.CONTRACT) {
                    // Ensure that the numerator and denominator are both equal to 1.
                    assembly {
                        // (1 ^ nd =/= 0) => (nd =/= 1) => (n =/= 1) || (d =/= 1)
                        // It's important that the values are 120-bit masked before
                        // multiplication is applied. Otherwise, the last implication
                        // above is not correct (mod 2^256).
                        invalidFraction := xor(mul(numerator, denominator), 1)
                    }
                    // Revert if the supplied numerator and denominator are not valid.
                    if (invalidFraction) {
                        _revertBadFraction();
                    }
                    // Return a placeholder orderHash and a fill fraction of 1/1.
                    // The real orderHash will be returned by _getGeneratedOrder.
                    return (bytes32(uint256(1)), 1, 1);
                }
                // Ensure numerator does not exceed denominator and is not zero.
                assembly {
                    invalidFraction := or(gt(numerator, denominator), iszero(numerator))
                }
                // Revert if the supplied numerator and denominator are not valid.
                if (invalidFraction) {
                    _revertBadFraction();
                }
                // If attempting partial fill (n < d) check order type & ensure support.
                if (
                    _doesNotSupportPartialFills(
                        orderParameters.orderType,
                        numerator,
                        denominator
                    )
                ) {
                    // Revert if partial fill was attempted on an unsupported order.
                    _revertPartialFillsNotEnabledForOrder();
                }
                // Retrieve current counter & use it w/ parameters to derive order hash.
                orderHash = _assertConsiderationLengthAndGetOrderHash(orderParameters);
                // Retrieve the order status using the derived order hash.
                OrderStatus storage orderStatus = _orderStatus[orderHash];
                // Ensure order is fillable and is not cancelled.
                if (
                    // Allow partially used orders to be filled.
                    !_verifyOrderStatus(orderHash, orderStatus, false, revertOnInvalid)
                ) {
                    // Assuming an invalid order status and no revert, return zero fill.
                    return (orderHash, 0, 0);
                }
                // If the order is not already validated, verify the supplied signature.
                if (!orderStatus.isValidated) {
                    _verifySignature(
                        orderParameters.offerer,
                        orderHash,
                        advancedOrder.signature
                    );
                }
                // Utilize assembly to determine the fraction to fill and update status.
                assembly {
                    let orderStatusSlot := orderStatus.slot
                    // Read filled amount as numerator and denominator and put on stack.
                    let filledNumerator := sload(orderStatusSlot)
                    let filledDenominator := shr(
                        OrderStatus_filledDenominator_offset,
                        filledNumerator
                    )
                    // "Loop" until the appropriate fill fraction has been determined.
                    for {
                    } 1 {
                    } {
                        // If no portion of the order has been filled yet...
                        if iszero(filledDenominator) {
                            // fill the full supplied fraction.
                            filledNumerator := numerator
                            // Exit the "loop" early.
                            break
                        }
                        // Shift and mask to calculate the current filled numerator.
                        filledNumerator := and(
                            shr(OrderStatus_filledNumerator_offset, filledNumerator),
                            MaxUint120
                        )
                        // If denominator of 1 supplied, fill entire remaining amount.
                        if eq(denominator, 1) {
                            // Set the amount to fill to the remaining amount.
                            numerator := sub(filledDenominator, filledNumerator)
                            // Set the fill size to the current size.
                            denominator := filledDenominator
                            // Exit the "loop" early.
                            break
                        }
                        // If supplied denominator is equal to the current one:
                        if eq(denominator, filledDenominator) {
                            // Increment the filled numerator by the new numerator.
                            filledNumerator := add(numerator, filledNumerator)
                            // Once adjusted, if current + supplied numerator exceeds
                            // the denominator:
                            let carry := mul(
                                sub(filledNumerator, denominator),
                                gt(filledNumerator, denominator)
                            )
                            // reduce the amount to fill by the excess.
                            numerator := sub(numerator, carry)
                            // Exit the "loop" early.
                            break
                        }
                        // Otherwise, if supplied denominator differs from current one:
                        // Scale the filled amount up by the supplied size.
                        filledNumerator := mul(filledNumerator, denominator)
                        // Scale the supplied amount and size up by the current size.
                        numerator := mul(numerator, filledDenominator)
                        denominator := mul(denominator, filledDenominator)
                        // Increment the filled numerator by the new numerator.
                        filledNumerator := add(numerator, filledNumerator)
                        // Once adjusted, if current + supplied numerator exceeds
                        // denominator:
                        let carry := mul(
                            sub(filledNumerator, denominator),
                            gt(filledNumerator, denominator)
                        )
                        // reduce the amount to fill by the excess.
                        numerator := sub(numerator, carry)
                        // Reduce the filled amount by the excess as well.
                        filledNumerator := sub(filledNumerator, carry)
                        // Check denominator for uint120 overflow.
                        if gt(denominator, MaxUint120) {
                            // Derive greatest common divisor using euclidean algorithm.
                            function gcd(_a, _b) -> out {
                                // "Loop" until only one non-zero value remains.
                                for {
                                } _b {
                                } {
                                    // Assign the second value to a temporary variable.
                                    let _c := _b
                                    // Derive the modulus of the two values.
                                    _b := mod(_a, _c)
                                    // Set the first value to the temporary value.
                                    _a := _c
                                }
                                // Return the remaining non-zero value.
                                out := _a
                            }
                            // Determine the amount to scale down the fill fractions.
                            let scaleDown := gcd(
                                numerator,
                                gcd(filledNumerator, denominator)
                            )
                            // Ensure that the divisor is at least one.
                            let safeScaleDown := add(scaleDown, iszero(scaleDown))
                            // Scale fractional values down by gcd.
                            numerator := div(numerator, safeScaleDown)
                            denominator := div(denominator, safeScaleDown)
                            // Perform the overflow check a second time.
                            if gt(denominator, MaxUint120) {
                                // Store the Panic error signature.
                                mstore(0, Panic_error_selector)
                                // Store the arithmetic (0x11) panic code.
                                mstore(Panic_error_code_ptr, Panic_arithmetic)
                                // revert(abi.encodeWithSignature(
                                //     "Panic(uint256)", 0x11
                                // ))
                                revert(Error_selector_offset, Panic_error_length)
                            }
                        }
                        // Exit the "loop" now that all evaluation is complete.
                        break
                    }
                }
            }
            /**
             * @dev Internal function to update the status of an order by applying the
             *      supplied fill fraction to the remaining order fraction. If
             *      revertOnInvalid is true, the function will revert if the order is
             *      unavailable or if it is not possible to apply the supplied fill
             *      fraction to the remaining amount (e.g., if there is not enough
             *      of the order remaining to fill the supplied fraction, or if the
             *      fractions cannot be represented by two uint120 values).
             *
             * @param orderHash       The hash of the order.
             * @param numerator       The numerator of the fraction filled to write to
             *                        the order status.
             * @param denominator     The denominator of the fraction filled to write to
             *                        the order status.
             * @param revertOnInvalid Whether to revert if an order is already filled.
             */
            function _updateStatus(
                bytes32 orderHash,
                uint256 numerator,
                uint256 denominator,
                bool revertOnInvalid
            ) internal returns (bool) {
                // Retrieve the order status using the derived order hash.
                OrderStatus storage orderStatus = _orderStatus[orderHash];
                bool hasCarry = false;
                uint256 orderStatusSlot;
                uint256 filledNumerator;
                // Utilize assembly to determine the fraction to fill and update status.
                assembly {
                    orderStatusSlot := orderStatus.slot
                    // Read filled amount as numerator and denominator and put on stack.
                    filledNumerator := sload(orderStatusSlot)
                    let filledDenominator := shr(
                        OrderStatus_filledDenominator_offset,
                        filledNumerator
                    )
                    // "Loop" until the appropriate fill fraction has been determined.
                    for {
                    } 1 {
                    } {
                        // If no portion of the order has been filled yet...
                        if iszero(filledDenominator) {
                            // fill the full supplied fraction.
                            filledNumerator := numerator
                            // Exit the "loop" early.
                            break
                        }
                        // Shift and mask to calculate the current filled numerator.
                        filledNumerator := and(
                            shr(OrderStatus_filledNumerator_offset, filledNumerator),
                            MaxUint120
                        )
                        // If supplied denominator is equal to the current one:
                        if eq(denominator, filledDenominator) {
                            // Increment the filled numerator by the new numerator.
                            filledNumerator := add(numerator, filledNumerator)
                            hasCarry := gt(filledNumerator, denominator)
                            // Exit the "loop" early.
                            break
                        }
                        // Otherwise, if supplied denominator differs from current one:
                        // Scale the filled amount up by the supplied size.
                        filledNumerator := mul(filledNumerator, denominator)
                        // Scale the supplied amount and size up by the current size.
                        numerator := mul(numerator, filledDenominator)
                        denominator := mul(denominator, filledDenominator)
                        // Increment the filled numerator by the new numerator.
                        filledNumerator := add(numerator, filledNumerator)
                        hasCarry := gt(filledNumerator, denominator)
                        // Check filledNumerator and denominator for uint120 overflow.
                        if or(
                            gt(filledNumerator, MaxUint120),
                            gt(denominator, MaxUint120)
                        ) {
                            // Derive greatest common divisor using euclidean algorithm.
                            function gcd(_a, _b) -> out {
                                // "Loop" until only one non-zero value remains.
                                for {
                                } _b {
                                } {
                                    // Assign the second value to a temporary variable.
                                    let _c := _b
                                    // Derive the modulus of the two values.
                                    _b := mod(_a, _c)
                                    // Set the first value to the temporary value.
                                    _a := _c
                                }
                                // Return the remaining non-zero value.
                                out := _a
                            }
                            // Determine amount to scale down the new filled fraction.
                            let scaleDown := gcd(filledNumerator, denominator)
                            // Ensure that the divisor is at least one.
                            let safeScaleDown := add(scaleDown, iszero(scaleDown))
                            // Scale new filled fractional values down by gcd.
                            filledNumerator := div(filledNumerator, safeScaleDown)
                            denominator := div(denominator, safeScaleDown)
                            // Perform the overflow check a second time.
                            if or(
                                gt(filledNumerator, MaxUint120),
                                gt(denominator, MaxUint120)
                            ) {
                                // Store the Panic error signature.
                                mstore(0, Panic_error_selector)
                                // Store the arithmetic (0x11) panic code.
                                mstore(Panic_error_code_ptr, Panic_arithmetic)
                                // revert(abi.encodeWithSignature(
                                //     "Panic(uint256)", 0x11
                                // ))
                                revert(Error_selector_offset, Panic_error_length)
                            }
                        }
                        // Exit the "loop" now that all evaluation is complete.
                        break
                    }
                }
                if (hasCarry) {
                    if (revertOnInvalid) {
                        revert OrderAlreadyFilled(orderHash);
                    } else {
                        return false;
                    }
                }
                assembly {
                    // Update order status and fill amount, packing struct values.
                    // [denominator: 15 bytes] [numerator: 15 bytes]
                    // [isCancelled: 1 byte] [isValidated: 1 byte]
                    sstore(
                        orderStatusSlot,
                        or(
                            OrderStatus_ValidatedAndNotCancelled,
                            or(
                                shl(
                                    OrderStatus_filledNumerator_offset,
                                    filledNumerator
                                ),
                                shl(OrderStatus_filledDenominator_offset, denominator)
                            )
                        )
                    )
                }
                return true;
            }
            /**
             * @dev Internal function to generate a contract order. When a
             *      collection-wide criteria-based item (criteria = 0) is provided as an
             *      input to a contract order, the contract offerer has full latitude to
             *      choose any identifier it wants mid-flight, which differs from the
             *      usual behavior.  For regular criteria-based orders with
             *      identifierOrCriteria = 0, the fulfiller can pick which identifier to
             *      receive by providing a CriteriaResolver. For contract offers with
             *      identifierOrCriteria = 0, Seaport does not expect a corresponding
             *      CriteriaResolver, and will revert if one is provided.
             *
             * @param orderParameters The parameters for the order.
             * @param context         The context for generating the order.
             * @param revertOnInvalid Whether to revert on invalid input.
             *
             * @return orderHash   The order hash.
             */
            function _getGeneratedOrder(
                OrderParameters memory orderParameters,
                bytes memory context,
                bool revertOnInvalid
            ) internal returns (bytes32 orderHash) {
                // Ensure that consideration array length is equal to the total original
                // consideration items value.
                if (
                    orderParameters.consideration.length !=
                    orderParameters.totalOriginalConsiderationItems
                ) {
                    _revertConsiderationLengthNotEqualToTotalOriginal();
                }
                {
                    address offerer = orderParameters.offerer;
                    bool success;
                    (MemoryPointer cdPtr, uint256 size) = _encodeGenerateOrder(
                        orderParameters,
                        context
                    );
                    assembly {
                        success := call(gas(), offerer, 0, cdPtr, size, 0, 0)
                    }
                    {
                        // Note: overflow impossible; nonce can't increment that high.
                        uint256 contractNonce;
                        unchecked {
                            // Note: nonce will be incremented even for skipped orders,
                            // and even if generateOrder's return data does not satisfy
                            // all the constraints. This is the case when errorBuffer
                            // != 0 and revertOnInvalid == false.
                            contractNonce = _contractNonces[offerer]++;
                        }
                        assembly {
                            // Shift offerer address up 96 bytes and combine with nonce.
                            orderHash := xor(
                                contractNonce,
                                shl(ContractOrder_orderHash_offerer_shift, offerer)
                            )
                        }
                    }
                    // Revert or skip if the call to generate the contract order failed.
                    if (!success) {
                        if (revertOnInvalid) {
                            _revertWithReasonIfOneIsReturned();
                            _revertInvalidContractOrder(orderHash);
                        }
                        return bytes32(0);
                    }
                }
                // From this point onward, do not allow for skipping orders as the
                // contract offerer may have modified state in expectation of any named
                // consideration items being sent to their designated recipients.
                // Decode the returned contract order and/or update the error buffer.
                (
                    uint256 errorBuffer,
                    OfferItem[] memory offer,
                    ConsiderationItem[] memory consideration
                ) = _convertGetGeneratedOrderResult(_decodeGenerateOrderReturndata)(
                        orderParameters.offer,
                        orderParameters.consideration
                    );
                // Revert if the returndata could not be decoded correctly.
                if (errorBuffer != 0) {
                    _revertInvalidContractOrder(orderHash);
                }
                // Assign the returned offer item in place of the original item.
                orderParameters.offer = offer;
                // Assign returned consideration item in place of the original item.
                orderParameters.consideration = consideration;
                // Return the order hash.
                return orderHash;
            }
            /**
             * @dev Internal function to cancel an arbitrary number of orders. Note that
             *      only the offerer or the zone of a given order may cancel it. Callers
             *      should ensure that the intended order was cancelled by calling
             *      `getOrderStatus` and confirming that `isCancelled` returns `true`.
             *      Also note that contract orders are not cancellable.
             *
             * @param orders The orders to cancel.
             *
             * @return cancelled A boolean indicating whether the supplied orders were
             *                   successfully cancelled.
             */
            function _cancel(
                OrderComponents[] calldata orders
            ) internal returns (bool cancelled) {
                // Ensure that the reentrancy guard is not currently set.
                _assertNonReentrant();
                // Declare variables outside of the loop.
                OrderStatus storage orderStatus;
                // Declare a variable for tracking invariants in the loop.
                bool anyInvalidCallerOrContractOrder;
                // Skip overflow check as for loop is indexed starting at zero.
                unchecked {
                    // Read length of the orders array from memory and place on stack.
                    uint256 totalOrders = orders.length;
                    // Iterate over each order.
                    for (uint256 i = 0; i < totalOrders; ) {
                        // Retrieve the order.
                        OrderComponents calldata order = orders[i];
                        address offerer = order.offerer;
                        address zone = order.zone;
                        OrderType orderType = order.orderType;
                        assembly {
                            // If caller is neither the offerer nor zone, or a contract
                            // order is present, flag anyInvalidCallerOrContractOrder.
                            anyInvalidCallerOrContractOrder := or(
                                anyInvalidCallerOrContractOrder,
                                // orderType == CONTRACT ||
                                // !(caller == offerer || caller == zone)
                                or(
                                    eq(orderType, 4),
                                    iszero(
                                        or(eq(caller(), offerer), eq(caller(), zone))
                                    )
                                )
                            )
                        }
                        bytes32 orderHash = _deriveOrderHash(
                            _toOrderParametersReturnType(
                                _decodeOrderComponentsAsOrderParameters
                            )(order.toCalldataPointer()),
                            order.counter
                        );
                        // Retrieve the order status using the derived order hash.
                        orderStatus = _orderStatus[orderHash];
                        // Update the order status as not valid and cancelled.
                        orderStatus.isValidated = false;
                        orderStatus.isCancelled = true;
                        // Emit an event signifying that the order has been cancelled.
                        emit OrderCancelled(orderHash, offerer, zone);
                        // Increment counter inside body of loop for gas efficiency.
                        ++i;
                    }
                }
                if (anyInvalidCallerOrContractOrder) {
                    _revertCannotCancelOrder();
                }
                // Return a boolean indicating that orders were successfully cancelled.
                cancelled = true;
            }
            /**
             * @dev Internal function to validate an arbitrary number of orders, thereby
             *      registering their signatures as valid and allowing the fulfiller to
             *      skip signature verification on fulfillment. Note that validated
             *      orders may still be unfulfillable due to invalid item amounts or
             *      other factors; callers should determine whether validated orders are
             *      fulfillable by simulating the fulfillment call prior to execution.
             *      Also note that anyone can validate a signed order, but only the
             *      offerer can validate an order without supplying a signature.
             *
             * @param orders The orders to validate.
             *
             * @return validated A boolean indicating whether the supplied orders were
             *                   successfully validated.
             */
            function _validate(
                Order[] memory orders
            ) internal returns (bool validated) {
                // Ensure that the reentrancy guard is not currently set.
                _assertNonReentrant();
                // Declare variables outside of the loop.
                OrderStatus storage orderStatus;
                bytes32 orderHash;
                address offerer;
                // Skip overflow check as for loop is indexed starting at zero.
                unchecked {
                    // Read length of the orders array from memory and place on stack.
                    uint256 totalOrders = orders.length;
                    // Iterate over each order.
                    for (uint256 i = 0; i < totalOrders; ++i) {
                        // Retrieve the order.
                        Order memory order = orders[i];
                        // Retrieve the order parameters.
                        OrderParameters memory orderParameters = order.parameters;
                        // Skip contract orders.
                        if (orderParameters.orderType == OrderType.CONTRACT) {
                            continue;
                        }
                        // Move offerer from memory to the stack.
                        offerer = orderParameters.offerer;
                        // Get current counter & use it w/ params to derive order hash.
                        orderHash = _assertConsiderationLengthAndGetOrderHash(
                            orderParameters
                        );
                        // Retrieve the order status using the derived order hash.
                        orderStatus = _orderStatus[orderHash];
                        // Ensure order is fillable and retrieve the filled amount.
                        _verifyOrderStatus(
                            orderHash,
                            orderStatus,
                            false, // Signifies that partially filled orders are valid.
                            _runTimeConstantTrue() // Revert if order is invalid.
                        );
                        // If the order has not already been validated...
                        if (!orderStatus.isValidated) {
                            // Ensure that consideration array length is equal to the
                            // total original consideration items value.
                            if (
                                orderParameters.consideration.length !=
                                orderParameters.totalOriginalConsiderationItems
                            ) {
                                _revertConsiderationLengthNotEqualToTotalOriginal();
                            }
                            // Verify the supplied signature.
                            _verifySignature(offerer, orderHash, order.signature);
                            // Update order status to mark the order as valid.
                            orderStatus.isValidated = true;
                            // Emit an event signifying the order has been validated.
                            emit OrderValidated(orderHash, orderParameters);
                        }
                    }
                }
                // Return a boolean indicating that orders were successfully validated.
                validated = true;
            }
            /**
             * @dev Internal view function to retrieve the status of a given order by
             *      hash, including whether the order has been cancelled or validated
             *      and the fraction of the order that has been filled.
             *
             * @param orderHash The order hash in question.
             *
             * @return isValidated A boolean indicating whether the order in question
             *                     has been validated (i.e. previously approved or
             *                     partially filled).
             * @return isCancelled A boolean indicating whether the order in question
             *                     has been cancelled.
             * @return totalFilled The total portion of the order that has been filled
             *                     (i.e. the "numerator").
             * @return totalSize   The total size of the order that is either filled or
             *                     unfilled (i.e. the "denominator").
             */
            function _getOrderStatus(
                bytes32 orderHash
            )
                internal
                view
                returns (
                    bool isValidated,
                    bool isCancelled,
                    uint256 totalFilled,
                    uint256 totalSize
                )
            {
                // Retrieve the order status using the order hash.
                OrderStatus storage orderStatus = _orderStatus[orderHash];
                // Return the fields on the order status.
                return (
                    orderStatus.isValidated,
                    orderStatus.isCancelled,
                    orderStatus.numerator,
                    orderStatus.denominator
                );
            }
            /**
             * @dev Internal pure function to check whether a given order type indicates
             *      that partial fills are not supported (e.g. only "full fills" are
             *      allowed for the order in question).
             *
             * @param orderType   The order type in question.
             * @param numerator   The numerator in question.
             * @param denominator The denominator in question.
             *
             * @return isFullOrder A boolean indicating whether the order type only
             *                     supports full fills.
             */
            function _doesNotSupportPartialFills(
                OrderType orderType,
                uint256 numerator,
                uint256 denominator
            ) internal pure returns (bool isFullOrder) {
                // The "full" order types are even, while "partial" order types are odd.
                // Bitwise and by 1 is equivalent to modulo by 2, but 2 gas cheaper. The
                // check is only necessary if numerator is less than denominator.
                assembly {
                    // Equivalent to `uint256(orderType) & 1 == 0`.
                    isFullOrder := and(
                        lt(numerator, denominator),
                        iszero(and(orderType, 1))
                    )
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import { Side } from "../lib/ConsiderationEnums.sol";
        /**
         * @title CriteriaResolutionErrors
         * @author 0age
         * @notice CriteriaResolutionErrors contains all errors related to criteria
         *         resolution.
         */
        interface CriteriaResolutionErrors {
            /**
             * @dev Revert with an error when providing a criteria resolver that refers
             *      to an order that has not been supplied.
             *
             * @param side The side of the order that was not supplied.
             */
            error OrderCriteriaResolverOutOfRange(Side side);
            /**
             * @dev Revert with an error if an offer item still has unresolved criteria
             *      after applying all criteria resolvers.
             *
             * @param orderIndex The index of the order that contains the offer item.
             * @param offerIndex The index of the offer item that still has unresolved
             *                   criteria.
             */
            error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex);
            /**
             * @dev Revert with an error if a consideration item still has unresolved
             *      criteria after applying all criteria resolvers.
             *
             * @param orderIndex         The index of the order that contains the
             *                           consideration item.
             * @param considerationIndex The index of the consideration item that still
             *                           has unresolved criteria.
             */
            error UnresolvedConsiderationCriteria(
                uint256 orderIndex,
                uint256 considerationIndex
            );
            /**
             * @dev Revert with an error when providing a criteria resolver that refers
             *      to an order with an offer item that has not been supplied.
             */
            error OfferCriteriaResolverOutOfRange();
            /**
             * @dev Revert with an error when providing a criteria resolver that refers
             *      to an order with a consideration item that has not been supplied.
             */
            error ConsiderationCriteriaResolverOutOfRange();
            /**
             * @dev Revert with an error when providing a criteria resolver that refers
             *      to an order with an item that does not expect a criteria to be
             *      resolved.
             */
            error CriteriaNotEnabledForItem();
            /**
             * @dev Revert with an error when providing a criteria resolver that
             *      contains an invalid proof with respect to the given item and
             *      chosen identifier.
             */
            error InvalidProof();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title AmountDerivationErrors
         * @author 0age
         * @notice AmountDerivationErrors contains errors related to amount derivation.
         */
        interface AmountDerivationErrors {
            /**
             * @dev Revert with an error when attempting to apply a fraction as part of
             *      a partial fill that does not divide the target amount cleanly.
             */
            error InexactFraction();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ConduitInterface
        } from "seaport-types/src/interfaces/ConduitInterface.sol";
        import {
            ConduitItemType
        } from "seaport-types/src/conduit/lib/ConduitEnums.sol";
        import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import { ReceivedItem } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { Verifiers } from "./Verifiers.sol";
        import { TokenTransferrer } from "./TokenTransferrer.sol";
        import {
            Accumulator_array_length_ptr,
            Accumulator_array_offset_ptr,
            Accumulator_array_offset,
            Accumulator_conduitKey_ptr,
            Accumulator_itemSizeOffsetDifference,
            Accumulator_selector_ptr,
            AccumulatorArmed,
            AccumulatorDisarmed,
            Conduit_transferItem_amount_ptr,
            Conduit_transferItem_from_ptr,
            Conduit_transferItem_identifier_ptr,
            Conduit_transferItem_size,
            Conduit_transferItem_to_ptr,
            Conduit_transferItem_token_ptr,
            FreeMemoryPointerSlot,
            OneWord,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            NativeTokenTransferGenericFailure_error_account_ptr,
            NativeTokenTransferGenericFailure_error_amount_ptr,
            NativeTokenTransferGenericFailure_error_length,
            NativeTokenTransferGenericFailure_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        import {
            _revertInvalidCallToConduit,
            _revertInvalidConduit,
            _revertInvalidERC721TransferAmount,
            _revertUnusedItemParameters
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        /**
         * @title Executor
         * @author 0age
         * @notice Executor contains functions related to processing executions (i.e.
         *         transferring items, either directly or via conduits).
         */
        contract Executor is Verifiers, TokenTransferrer {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) Verifiers(conduitController) {}
            /**
             * @dev Internal function to transfer a given item, either directly or via
             *      a corresponding conduit.
             *
             * @param item        The item to transfer, including an amount and a
             *                    recipient.
             * @param from        The account supplying the item.
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _transfer(
                ReceivedItem memory item,
                address from,
                bytes32 conduitKey,
                bytes memory accumulator
            ) internal {
                // If the item type indicates Ether or a native token...
                if (item.itemType == ItemType.NATIVE) {
                    // Ensure neither the token nor the identifier parameters are set.
                    if ((uint160(item.token) | item.identifier) != 0) {
                        _revertUnusedItemParameters();
                    }
                    // transfer the native tokens to the recipient.
                    _transferNativeTokens(item.recipient, item.amount);
                } else if (item.itemType == ItemType.ERC20) {
                    // Ensure that no identifier is supplied.
                    if (item.identifier != 0) {
                        _revertUnusedItemParameters();
                    }
                    // Transfer ERC20 tokens from the source to the recipient.
                    _transferERC20(
                        item.token,
                        from,
                        item.recipient,
                        item.amount,
                        conduitKey,
                        accumulator
                    );
                } else if (item.itemType == ItemType.ERC721) {
                    // Transfer ERC721 token from the source to the recipient.
                    _transferERC721(
                        item.token,
                        from,
                        item.recipient,
                        item.identifier,
                        item.amount,
                        conduitKey,
                        accumulator
                    );
                } else {
                    // Transfer ERC1155 token from the source to the recipient.
                    _transferERC1155(
                        item.token,
                        from,
                        item.recipient,
                        item.identifier,
                        item.amount,
                        conduitKey,
                        accumulator
                    );
                }
            }
            /**
             * @dev Internal function to transfer Ether or other native tokens to a
             *      given recipient.
             *
             * @param to     The recipient of the transfer.
             * @param amount The amount to transfer.
             */
            function _transferNativeTokens(
                address payable to,
                uint256 amount
            ) internal {
                // Ensure that the supplied amount is non-zero.
                _assertNonZeroAmount(amount);
                // Declare a variable indicating whether the call was successful or not.
                bool success;
                assembly {
                    // Transfer the native token and store if it succeeded or not.
                    success := call(gas(), to, amount, 0, 0, 0, 0)
                }
                // If the call fails...
                if (!success) {
                    // Revert and pass the revert reason along if one was returned.
                    _revertWithReasonIfOneIsReturned();
                    // Otherwise, revert with a generic error message.
                    assembly {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, NativeTokenTransferGenericFailure_error_selector)
                        // Write `to` and `amount` arguments.
                        mstore(NativeTokenTransferGenericFailure_error_account_ptr, to)
                        mstore(
                            NativeTokenTransferGenericFailure_error_amount_ptr,
                            amount
                        )
                        // revert(abi.encodeWithSignature(
                        //     "NativeTokenTransferGenericFailure(address,uint256)",
                        //     to,
                        //     amount
                        // ))
                        revert(
                            Error_selector_offset,
                            NativeTokenTransferGenericFailure_error_length
                        )
                    }
                }
            }
            /**
             * @dev Internal function to transfer ERC20 tokens from a given originator
             *      to a given recipient using a given conduit if applicable. Sufficient
             *      approvals must be set on this contract or on a respective conduit.
             *
             * @param token       The ERC20 token to transfer.
             * @param from        The originator of the transfer.
             * @param to          The recipient of the transfer.
             * @param amount      The amount to transfer.
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _transferERC20(
                address token,
                address from,
                address to,
                uint256 amount,
                bytes32 conduitKey,
                bytes memory accumulator
            ) internal {
                // Ensure that the supplied amount is non-zero.
                _assertNonZeroAmount(amount);
                // Trigger accumulated transfers if the conduits differ.
                _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
                // If no conduit has been specified...
                if (conduitKey == bytes32(0)) {
                    // Perform the token transfer directly.
                    _performERC20Transfer(token, from, to, amount);
                } else {
                    // Insert the call to the conduit into the accumulator.
                    _insert(
                        conduitKey,
                        accumulator,
                        ConduitItemType.ERC20,
                        token,
                        from,
                        to,
                        uint256(0),
                        amount
                    );
                }
            }
            /**
             * @dev Internal function to transfer a single ERC721 token from a given
             *      originator to a given recipient. Sufficient approvals must be set,
             *      either on the respective conduit or on this contract itself.
             *
             * @param token       The ERC721 token to transfer.
             * @param from        The originator of the transfer.
             * @param to          The recipient of the transfer.
             * @param identifier  The tokenId to transfer.
             * @param amount      The amount to transfer (must be 1 for ERC721).
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _transferERC721(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount,
                bytes32 conduitKey,
                bytes memory accumulator
            ) internal {
                // Trigger accumulated transfers if the conduits differ.
                _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
                // If no conduit has been specified...
                if (conduitKey == bytes32(0)) {
                    // Ensure that exactly one 721 item is being transferred.
                    if (amount != 1) {
                        _revertInvalidERC721TransferAmount(amount);
                    }
                    // Perform transfer via the token contract directly.
                    _performERC721Transfer(token, from, to, identifier);
                } else {
                    // Insert the call to the conduit into the accumulator.
                    _insert(
                        conduitKey,
                        accumulator,
                        ConduitItemType.ERC721,
                        token,
                        from,
                        to,
                        identifier,
                        amount
                    );
                }
            }
            /**
             * @dev Internal function to transfer ERC1155 tokens from a given originator
             *      to a given recipient. Sufficient approvals must be set, either on
             *      the respective conduit or on this contract itself.
             *
             * @param token       The ERC1155 token to transfer.
             * @param from        The originator of the transfer.
             * @param to          The recipient of the transfer.
             * @param identifier  The id to transfer.
             * @param amount      The amount to transfer.
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _transferERC1155(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount,
                bytes32 conduitKey,
                bytes memory accumulator
            ) internal {
                // Ensure that the supplied amount is non-zero.
                _assertNonZeroAmount(amount);
                // Trigger accumulated transfers if the conduits differ.
                _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
                // If no conduit has been specified...
                if (conduitKey == bytes32(0)) {
                    // Perform transfer via the token contract directly.
                    _performERC1155Transfer(token, from, to, identifier, amount);
                } else {
                    // Insert the call to the conduit into the accumulator.
                    _insert(
                        conduitKey,
                        accumulator,
                        ConduitItemType.ERC1155,
                        token,
                        from,
                        to,
                        identifier,
                        amount
                    );
                }
            }
            /**
             * @dev Internal function to trigger a call to the conduit currently held by
             *      the accumulator if the accumulator contains item transfers (i.e. it
             *      is "armed") and the supplied conduit key does not match the key held
             *      by the accumulator.
             *
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             */
            function _triggerIfArmedAndNotAccumulatable(
                bytes memory accumulator,
                bytes32 conduitKey
            ) internal {
                // Retrieve the current conduit key from the accumulator.
                bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
                // Perform conduit call if the set key does not match the supplied key.
                if (accumulatorConduitKey != conduitKey) {
                    _triggerIfArmed(accumulator);
                }
            }
            /**
             * @dev Internal function to trigger a call to the conduit currently held by
             *      the accumulator if the accumulator contains item transfers (i.e. it
             *      is "armed").
             *
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _triggerIfArmed(bytes memory accumulator) internal {
                // Exit if the accumulator is not "armed".
                if (accumulator.length != AccumulatorArmed) {
                    return;
                }
                // Retrieve the current conduit key from the accumulator.
                bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
                // Perform conduit call.
                _trigger(accumulatorConduitKey, accumulator);
            }
            /**
             * @dev Internal function to trigger a call to the conduit corresponding to
             *      a given conduit key, supplying all accumulated item transfers. The
             *      accumulator will be "disarmed" and reset in the process.
             *
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             */
            function _trigger(bytes32 conduitKey, bytes memory accumulator) internal {
                // Declare variables for offset in memory & size of calldata to conduit.
                uint256 callDataOffset;
                uint256 callDataSize;
                // Call the conduit with all the accumulated transfers.
                assembly {
                    // Call begins at third word; the first is length or "armed" status,
                    // and the second is the current conduit key.
                    callDataOffset := add(accumulator, TwoWords)
                    // 68 + items * 192
                    callDataSize := add(
                        Accumulator_array_offset_ptr,
                        mul(
                            mload(add(accumulator, Accumulator_array_length_ptr)),
                            Conduit_transferItem_size
                        )
                    )
                }
                // Call conduit derived from conduit key & supply accumulated transfers.
                _callConduitUsingOffsets(conduitKey, callDataOffset, callDataSize);
                // Reset accumulator length to signal that it is now "disarmed".
                assembly {
                    mstore(accumulator, AccumulatorDisarmed)
                }
            }
            /**
             * @dev Internal function to perform a call to the conduit corresponding to
             *      a given conduit key based on the offset and size of the calldata in
             *      question in memory.
             *
             * @param conduitKey     A bytes32 value indicating what corresponding
             *                       conduit, if any, to source token approvals from.
             *                       The zero hash signifies that no conduit should be
             *                       used, with direct approvals set on this contract.
             * @param callDataOffset The memory pointer where calldata is contained.
             * @param callDataSize   The size of calldata in memory.
             */
            function _callConduitUsingOffsets(
                bytes32 conduitKey,
                uint256 callDataOffset,
                uint256 callDataSize
            ) internal {
                // Derive the address of the conduit using the conduit key.
                address conduit = _deriveConduit(conduitKey);
                bool success;
                bytes4 result;
                // call the conduit.
                assembly {
                    // Ensure first word of scratch space is empty.
                    mstore(0, 0)
                    // Perform call, placing first word of return data in scratch space.
                    success := call(
                        gas(),
                        conduit,
                        0,
                        callDataOffset,
                        callDataSize,
                        0,
                        OneWord
                    )
                    // Take value from scratch space and place it on the stack.
                    result := mload(0)
                }
                // If the call failed...
                if (!success) {
                    // Pass along whatever revert reason was given by the conduit.
                    _revertWithReasonIfOneIsReturned();
                    // Otherwise, revert with a generic error.
                    _revertInvalidCallToConduit(conduit);
                }
                // Ensure result was extracted and matches magic value.
                if (result != ConduitInterface.execute.selector) {
                    _revertInvalidConduit(conduitKey, conduit);
                }
            }
            /**
             * @dev Internal pure function to retrieve the current conduit key set for
             *      the accumulator.
             *
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             *
             * @return accumulatorConduitKey The conduit key currently set for the
             *                               accumulator.
             */
            function _getAccumulatorConduitKey(
                bytes memory accumulator
            ) internal pure returns (bytes32 accumulatorConduitKey) {
                // Retrieve the current conduit key from the accumulator.
                assembly {
                    accumulatorConduitKey := mload(
                        add(accumulator, Accumulator_conduitKey_ptr)
                    )
                }
            }
            /**
             * @dev Internal pure function to place an item transfer into an accumulator
             *      that collects a series of transfers to execute against a given
             *      conduit in a single call.
             *
             * @param conduitKey  A bytes32 value indicating what corresponding conduit,
             *                    if any, to source token approvals from. The zero hash
             *                    signifies that no conduit should be used, with direct
             *                    approvals set on this contract.
             * @param accumulator An open-ended array that collects transfers to execute
             *                    against a given conduit in a single call.
             * @param itemType    The type of the item to transfer.
             * @param token       The token to transfer.
             * @param from        The originator of the transfer.
             * @param to          The recipient of the transfer.
             * @param identifier  The tokenId to transfer.
             * @param amount      The amount to transfer.
             */
            function _insert(
                bytes32 conduitKey,
                bytes memory accumulator,
                ConduitItemType itemType,
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount
            ) internal pure {
                uint256 elements;
                // "Arm" and prime accumulator if it's not already armed. The sentinel
                // value is held in the length of the accumulator array.
                if (accumulator.length == AccumulatorDisarmed) {
                    elements = 1;
                    bytes4 selector = ConduitInterface.execute.selector;
                    assembly {
                        mstore(accumulator, AccumulatorArmed) // "arm" the accumulator.
                        mstore(add(accumulator, Accumulator_conduitKey_ptr), conduitKey)
                        mstore(add(accumulator, Accumulator_selector_ptr), selector)
                        mstore(
                            add(accumulator, Accumulator_array_offset_ptr),
                            Accumulator_array_offset
                        )
                        mstore(add(accumulator, Accumulator_array_length_ptr), elements)
                    }
                } else {
                    // Otherwise, increase the number of elements by one.
                    assembly {
                        elements := add(
                            mload(add(accumulator, Accumulator_array_length_ptr)),
                            1
                        )
                        mstore(add(accumulator, Accumulator_array_length_ptr), elements)
                    }
                }
                // Insert the item.
                assembly {
                    let itemPointer := sub(
                        add(accumulator, mul(elements, Conduit_transferItem_size)),
                        Accumulator_itemSizeOffsetDifference
                    )
                    mstore(itemPointer, itemType)
                    mstore(add(itemPointer, Conduit_transferItem_token_ptr), token)
                    mstore(add(itemPointer, Conduit_transferItem_from_ptr), from)
                    mstore(add(itemPointer, Conduit_transferItem_to_ptr), to)
                    mstore(
                        add(itemPointer, Conduit_transferItem_identifier_ptr),
                        identifier
                    )
                    mstore(add(itemPointer, Conduit_transferItem_amount_ptr), amount)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import { OrderType } from "seaport-types/src/lib/ConsiderationEnums.sol";
        import {
            AdvancedOrder,
            BasicOrderParameters,
            OrderParameters
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            ZoneInteractionErrors
        } from "seaport-types/src/interfaces/ZoneInteractionErrors.sol";
        import { LowLevelHelpers } from "./LowLevelHelpers.sol";
        import { ConsiderationEncoder } from "./ConsiderationEncoder.sol";
        import {
            CalldataPointer,
            MemoryPointer,
            OffsetOrLengthMask,
            ZeroSlotPtr
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        import {
            authorizeOrder_selector_offset,
            BasicOrder_zone_cdPtr,
            ContractOrder_orderHash_offerer_shift,
            MaskOverFirstFourBytes,
            OneWord,
            OrderParameters_salt_offset,
            OrderParameters_zone_offset,
            validateOrder_selector_offset
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            InvalidContractOrder_error_selector,
            InvalidRestrictedOrder_error_length,
            InvalidRestrictedOrder_error_orderHash_ptr,
            InvalidRestrictedOrder_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title ZoneInteraction
         * @author 0age
         * @notice ZoneInteraction contains logic related to interacting with zones.
         */
        contract ZoneInteraction is
            ConsiderationEncoder,
            ZoneInteractionErrors,
            LowLevelHelpers
        {
            /**
             * @dev Internal function to determine if an order has a restricted order
             *      type and, if so, to ensure that either the zone is the caller or
             *      that a call to `validateOrder` on the zone returns a magic value
             *      indicating that the order is currently valid. Note that contract
             *      orders are not accessible via the basic fulfillment method.
             *
             * @param orderHash  The hash of the order.
             * @param orderType  The order type.
             */
            function _assertRestrictedBasicOrderAuthorization(
                bytes32 orderHash,
                OrderType orderType
            ) internal returns (uint256 callDataPointer) {
                // Order type 2-3 require zone be caller or zone to approve.
                // Note that in cases where fulfiller == zone, the restricted order
                // validation will be skipped.
                if (
                    _isRestrictedAndCallerNotZone(
                        orderType,
                        CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress()
                    )
                ) {
                    // Encode the `authorizeOrder` call in memory.
                    (
                        MemoryPointer callData,
                        uint256 size,
                        uint256 memoryLocationForOrderHashes
                    ) = _encodeAuthorizeBasicOrder(orderHash);
                    // Write the error selector to memory at the zero slot where it can
                    // be used to revert with a specific error message.
                    ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector);
                    // Perform `authorizeOrder` call & ensure magic value was returned.
                    _callAndCheckStatus(
                        CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress(),
                        orderHash,
                        callData.offset(authorizeOrder_selector_offset),
                        size
                    );
                    // Restore the zero slot.
                    ZeroSlotPtr.write(0);
                    // Register the calldata pointer for the encoded calldata.
                    callDataPointer = MemoryPointer.unwrap(callData);
                    // Utilize unchecked logic as size value cannot be so large as to
                    // cause an overflow.
                    unchecked {
                        // Write the packed encoding of size and memory location for
                        // order hashes to memory at the head of the encoded calldata.
                        callData.write(
                            ((size + OneWord) << 128) | memoryLocationForOrderHashes
                        );
                    }
                }
            }
            /**
             * @dev Internal function to determine if an order has a restricted order
             *      type and, if so, to ensure that either the zone is the caller or
             *      that a call to `validateOrder` on the zone returns a magic value
             *      indicating that the order is currently valid. Note that contract
             *      orders are not accessible via the basic fulfillment method.
             *
             * @param orderHash   The hash of the order.
             * @param orderType   The order type.
             * @param callDataPtr The pointer to the call data for the basic order.
             *                    Note that the initial value will contain the size
             *                    and the memory location for order hashes length.
             */
            function _assertRestrictedBasicOrderValidity(
                bytes32 orderHash,
                OrderType orderType,
                uint256 callDataPtr
            ) internal {
                // Order type 2-3 require zone be caller or zone to approve.
                // Note that in cases where fulfiller == zone, the restricted order
                // validation will be skipped.
                if (
                    _isRestrictedAndCallerNotZone(
                        orderType,
                        CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress()
                    )
                ) {
                    // Cast the call data pointer to a memory pointer.
                    MemoryPointer callData = MemoryPointer.wrap(callDataPtr);
                    // Retrieve the size and memory location for order hashes from the
                    // head of the encoded calldata where it was previously written.
                    uint256 sizeAndMemoryLocationForOrderHashes = (
                        callData.readUint256()
                    );
                    // Split the packed encoding to retrieve size and memory location.
                    uint256 size = sizeAndMemoryLocationForOrderHashes >> 128;
                    uint256 memoryLocationForOrderHashes = (
                        sizeAndMemoryLocationForOrderHashes & OffsetOrLengthMask
                    );
                    // Encode the `validateOrder` call in memory.
                    _encodeValidateBasicOrder(callData, memoryLocationForOrderHashes);
                    // Account for the offset of the selector in the encoded call data.
                    callData = callData.offset(validateOrder_selector_offset);
                    // Write the error selector to memory at the zero slot where it can
                    // be used to revert with a specific error message.
                    ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector);
                    // Perform `validateOrder` call and ensure magic value was returned.
                    _callAndCheckStatus(
                        CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress(),
                        orderHash,
                        callData,
                        size
                    );
                    // Restore the zero slot.
                    ZeroSlotPtr.write(0);
                }
            }
            /**
             * @dev Internal function to determine the pre-execution validity of
             *      restricted orders, signaling whether or not the order is valid.
             *      Restricted orders where the caller is not the zone must
             *      successfully call `authorizeOrder` with the correct magic value
             *      returned.
             *
             * @param advancedOrder   The advanced order in question.
             * @param orderHashes     The order hashes of each order included as part
             *                        of the current fulfillment.
             * @param orderHash       The hash of the order.
             * @param orderIndex      The index of the order.
             * @param revertOnInvalid Whether to revert if the call is invalid.
             *
             * @return isValid True if the order is valid, false otherwise (unless
             *                 revertOnInvalid is true, in which case this function
             *                 will revert).
             */
            function _checkRestrictedAdvancedOrderAuthorization(
                AdvancedOrder memory advancedOrder,
                bytes32[] memory orderHashes,
                bytes32 orderHash,
                uint256 orderIndex,
                bool revertOnInvalid
            ) internal returns (bool isValid) {
                // Retrieve the parameters of the order in question.
                OrderParameters memory parameters = advancedOrder.parameters;
                // OrderType 2-3 require zone to be caller or approve via validateOrder.
                if (
                    _isRestrictedAndCallerNotZone(parameters.orderType, parameters.zone)
                ) {
                    // Encode the `validateOrder` call in memory.
                    (MemoryPointer callData, uint256 size) = _encodeAuthorizeOrder(
                        orderHash,
                        parameters,
                        advancedOrder.extraData,
                        orderHashes,
                        orderIndex
                    );
                    // Perform call and ensure a corresponding magic value was returned.
                    return
                        _callAndCheckStatusWithSkip(
                            parameters.zone,
                            orderHash,
                            callData,
                            size,
                            InvalidRestrictedOrder_error_selector,
                            revertOnInvalid
                        );
                }
                return true;
            }
            /**
             * @dev Internal function to determine the pre-execution validity of
             *      restricted orders and to revert if the order is invalid.
             *      Restricted orders where the caller is not the zone must
             *      successfully call `authorizeOrder` with the correct magic value
             *      returned.
             *
             * @param advancedOrder   The advanced order in question.
             * @param orderHashes     The order hashes of each order included as part
             *                        of the current fulfillment.
             * @param orderHash       The hash of the order.
             * @param orderIndex      The index of the order.
             */
            function _assertRestrictedAdvancedOrderAuthorization(
                AdvancedOrder memory advancedOrder,
                bytes32[] memory orderHashes,
                bytes32 orderHash,
                uint256 orderIndex
            ) internal {
                // Retrieve the parameters of the order in question.
                OrderParameters memory parameters = advancedOrder.parameters;
                // OrderType 2-3 requires zone to call or approve via authorizeOrder.
                if (
                    _isRestrictedAndCallerNotZone(parameters.orderType, parameters.zone)
                ) {
                    // Encode the `authorizeOrder` call in memory.
                    (MemoryPointer callData, uint256 size) = _encodeAuthorizeOrder(
                        orderHash,
                        parameters,
                        advancedOrder.extraData,
                        orderHashes,
                        orderIndex
                    );
                    // Write the error selector to memory at the zero slot where it can
                    // be used to revert with a specific error message.
                    ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector);
                    // Perform call and ensure a corresponding magic value was returned.
                    _callAndCheckStatus(parameters.zone, orderHash, callData, size);
                    // Restore the zero slot.
                    ZeroSlotPtr.write(0);
                }
            }
            /**
             * @dev Internal function to determine the post-execution validity of
             *      restricted and contract orders. Restricted orders where the caller
             *      is not the zone must successfully call `validateOrder` with the
             *      correct magic value returned. Contract orders must successfully call
             *      `ratifyOrder` with the correct magic value returned.
             *
             * @param advancedOrder The advanced order in question.
             * @param orderHashes   The order hashes of each order included as part of
             *                      the current fulfillment.
             * @param orderHash     The hash of the order.
             */
            function _assertRestrictedAdvancedOrderValidity(
                AdvancedOrder memory advancedOrder,
                bytes32[] memory orderHashes,
                bytes32 orderHash
            ) internal {
                // Declare variables that will be assigned based on the order type.
                address target;
                uint256 errorSelector;
                MemoryPointer callData;
                uint256 size;
                // Retrieve the parameters of the order in question.
                OrderParameters memory parameters = advancedOrder.parameters;
                // OrderType 2-3 require zone to be caller or approve via validateOrder.
                if (
                    _isRestrictedAndCallerNotZone(parameters.orderType, parameters.zone)
                ) {
                    // Encode the `validateOrder` call in memory.
                    (callData, size) = _encodeValidateOrder(
                        parameters
                            .toMemoryPointer()
                            .offset(OrderParameters_salt_offset)
                            .readUint256(),
                        orderHashes
                    );
                    // Set the target to the zone.
                    target = (
                        parameters
                            .toMemoryPointer()
                            .offset(OrderParameters_zone_offset)
                            .readAddress()
                    );
                    // Set the restricted-order-specific error selector.
                    errorSelector = InvalidRestrictedOrder_error_selector;
                } else if (parameters.orderType == OrderType.CONTRACT) {
                    // Set the target to the offerer (note the offerer has no offset).
                    target = parameters.toMemoryPointer().readAddress();
                    // Shift the target 96 bits to the left.
                    uint256 shiftedOfferer;
                    assembly {
                        shiftedOfferer := shl(
                            ContractOrder_orderHash_offerer_shift,
                            target
                        )
                    }
                    // Encode the `ratifyOrder` call in memory.
                    (callData, size) = _encodeRatifyOrder(
                        orderHash,
                        parameters,
                        advancedOrder.extraData,
                        orderHashes,
                        shiftedOfferer
                    );
                    // Set the contract-order-specific error selector.
                    errorSelector = InvalidContractOrder_error_selector;
                } else {
                    return;
                }
                // Write the error selector to memory at the zero slot where it can be
                // used to revert with a specific error message.
                ZeroSlotPtr.write(errorSelector);
                // Perform call and ensure a corresponding magic value was returned.
                _callAndCheckStatus(target, orderHash, callData, size);
                // Restore the zero slot.
                ZeroSlotPtr.write(0);
            }
            /**
             * @dev Determines whether the specified order type is restricted and the
             *      caller is not the specified zone.
             *
             * @param orderType     The type of the order to check.
             * @param zone          The address of the zone to check against.
             *
             * @return mustValidate True if the order type is restricted and the caller
             *                      is not the specified zone, false otherwise.
             */
            function _isRestrictedAndCallerNotZone(
                OrderType orderType,
                address zone
            ) internal view returns (bool mustValidate) {
                // Utilize assembly to efficiently perform the check.
                assembly {
                    mustValidate := and(
                        // Note that this check requires that there are no order
                        // types beyond the current set (0-4).  It will need to be
                        // modified if more order types are added.
                        and(lt(orderType, 4), gt(orderType, 1)),
                        iszero(eq(caller(), zone))
                    )
                }
            }
            /**
             * @dev Calls the specified target with the given data and checks the status
             *      of the call. Revert reasons will be "bubbled up" if one is returned,
             *      otherwise reverting calls will throw a generic error based on the
             *      supplied error handler. Note that the custom error selector must
             *      already be in memory at the zero slot when this function is called.
             *
             * @param target        The address of the contract to call.
             * @param orderHash     The hash of the order associated with the call.
             * @param callData      The data to pass to the contract call.
             * @param size          The size of calldata.
             */
            function _callAndCheckStatus(
                address target,
                bytes32 orderHash,
                MemoryPointer callData,
                uint256 size
            ) internal {
                bool success;
                bool magicMatch;
                assembly {
                    // Get magic value from the selector at start of provided calldata.
                    let magic := and(mload(callData), MaskOverFirstFourBytes)
                    // Clear the start of scratch space.
                    mstore(0, 0)
                    // Perform call, placing result in the first word of scratch space.
                    success := call(gas(), target, 0, callData, size, 0, OneWord)
                    // Determine if returned magic value matches the calldata selector.
                    magicMatch := eq(magic, mload(0))
                }
                // Revert if the call was not successful.
                if (!success) {
                    // Revert and pass reason along if one was returned.
                    _revertWithReasonIfOneIsReturned();
                    // If no reason was returned, revert with supplied error selector.
                    assembly {
                        // The error selector is already in memory at the zero slot.
                        mstore(0x80, orderHash)
                        // revert(abi.encodeWithSelector(
                        //     "InvalidRestrictedOrder(bytes32)",
                        //     orderHash
                        // ))
                        revert(0x7c, InvalidRestrictedOrder_error_length)
                    }
                }
                // Revert if the correct magic value was not returned.
                if (!magicMatch) {
                    // Revert with a generic error message.
                    assembly {
                        // The error selector is already in memory at the zero slot.
                        mstore(0x80, orderHash)
                        // revert(abi.encodeWithSelector(
                        //     "InvalidRestrictedOrder(bytes32)",
                        //     orderHash
                        // ))
                        revert(0x7c, InvalidRestrictedOrder_error_length)
                    }
                }
            }
            /**
             * @dev Calls the specified target with the given data and checks the status
             *      of the call. Revert reasons will be "bubbled up" if one is returned,
             *      otherwise reverting calls will throw a generic error based on the
             *      supplied error handler.
             *
             * @param target          The address of the contract to call.
             * @param orderHash       The hash of the order associated with the call.
             * @param callData        The data to pass to the contract call.
             * @param size            The size of calldata.
             * @param errorSelector   The error handling function to call if the call
             *                        fails or the magic value does not match.
             * @param revertOnInvalid Whether to revert if the call is invalid. Must
             *                        still revert if the call returns invalid data.
             */
            function _callAndCheckStatusWithSkip(
                address target,
                bytes32 orderHash,
                MemoryPointer callData,
                uint256 size,
                uint256 errorSelector,
                bool revertOnInvalid
            ) internal returns (bool) {
                bool success;
                bool magicMatch;
                assembly {
                    // Get magic value from the selector at start of provided calldata.
                    let magic := and(mload(callData), MaskOverFirstFourBytes)
                    // Clear the start of scratch space.
                    mstore(0, 0)
                    // Perform call, placing result in the first word of scratch space.
                    success := call(gas(), target, 0, callData, size, 0, OneWord)
                    // Determine if returned magic value matches the calldata selector.
                    magicMatch := eq(magic, mload(0))
                }
                // Revert or return false if the call was not successful.
                if (!success) {
                    if (!revertOnInvalid) {
                        return false;
                    }
                    // Revert and pass reason along if one was returned.
                    _revertWithReasonIfOneIsReturned();
                    // If no reason was returned, revert with supplied error selector.
                    assembly {
                        mstore(0, errorSelector)
                        mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash)
                        // revert(abi.encodeWithSelector(
                        //     "InvalidRestrictedOrder(bytes32)",
                        //     orderHash
                        // ))
                        revert(
                            Error_selector_offset,
                            InvalidRestrictedOrder_error_length
                        )
                    }
                }
                // Revert if the correct magic value was not returned.
                if (!magicMatch) {
                    // Revert with a generic error message.
                    assembly {
                        mstore(0, errorSelector)
                        mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash)
                        // revert(abi.encodeWithSelector(
                        //     "InvalidRestrictedOrder(bytes32)",
                        //     orderHash
                        // ))
                        revert(
                            Error_selector_offset,
                            InvalidRestrictedOrder_error_length
                        )
                    }
                }
                return true;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import {
            ConduitBatch1155Transfer,
            ConduitTransfer
        } from "../conduit/lib/ConduitStructs.sol";
        /**
         * @title ConduitInterface
         * @author 0age
         * @notice ConduitInterface contains all external function interfaces, events,
         *         and errors for conduit contracts.
         */
        interface ConduitInterface {
            /**
             * @dev Revert with an error when attempting to execute transfers using a
             *      caller that does not have an open channel.
             */
            error ChannelClosed(address channel);
            /**
             * @dev Revert with an error when attempting to update a channel to the
             *      current status of that channel.
             */
            error ChannelStatusAlreadySet(address channel, bool isOpen);
            /**
             * @dev Revert with an error when attempting to execute a transfer for an
             *      item that does not have an ERC20/721/1155 item type.
             */
            error InvalidItemType();
            /**
             * @dev Revert with an error when attempting to update the status of a
             *      channel from a caller that is not the conduit controller.
             */
            error InvalidController();
            /**
             * @dev Emit an event whenever a channel is opened or closed.
             *
             * @param channel The channel that has been updated.
             * @param open    A boolean indicating whether the conduit is open or not.
             */
            event ChannelUpdated(address indexed channel, bool open);
            /**
             * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
             *         with an open channel can call this function.
             *
             * @param transfers The ERC20/721/1155 transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function execute(
                ConduitTransfer[] calldata transfers
            ) external returns (bytes4 magicValue);
            /**
             * @notice Execute a sequence of batch 1155 transfers. Only a caller with an
             *         open channel can call this function.
             *
             * @param batch1155Transfers The 1155 batch transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function executeBatch1155(
                ConduitBatch1155Transfer[] calldata batch1155Transfers
            ) external returns (bytes4 magicValue);
            /**
             * @notice Execute a sequence of transfers, both single and batch 1155. Only
             *         a caller with an open channel can call this function.
             *
             * @param standardTransfers  The ERC20/721/1155 transfers to perform.
             * @param batch1155Transfers The 1155 batch transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function executeWithBatch1155(
                ConduitTransfer[] calldata standardTransfers,
                ConduitBatch1155Transfer[] calldata batch1155Transfers
            ) external returns (bytes4 magicValue);
            /**
             * @notice Open or close a given channel. Only callable by the controller.
             *
             * @param channel The channel to open or close.
             * @param isOpen  The status of the channel (either open or closed).
             */
            function updateChannel(address channel, bool isOpen) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        enum ConduitItemType {
            NATIVE, // unused
            ERC20,
            ERC721,
            ERC1155
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import { OrderStatus } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { Assertions } from "./Assertions.sol";
        import { SignatureVerification } from "./SignatureVerification.sol";
        import {
            _revertInvalidTime,
            _revertOrderAlreadyFilled,
            _revertOrderIsCancelled,
            _revertOrderPartiallyFilled
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            BulkOrderProof_keyShift,
            BulkOrderProof_keySize,
            BulkOrderProof_lengthAdjustmentBeforeMask,
            BulkOrderProof_lengthRangeAfterMask,
            BulkOrderProof_minSize,
            BulkOrderProof_rangeSize,
            ECDSA_MaxLength,
            OneWord,
            OneWordShift,
            ThirtyOneBytes,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        /**
         * @title Verifiers
         * @author 0age
         * @notice Verifiers contains functions for performing verifications.
         */
        contract Verifiers is Assertions, SignatureVerification {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) Assertions(conduitController) {}
            /**
             * @dev Internal view function to ensure that the current time falls within
             *      an order's valid timespan.
             *
             * @param startTime       The time at which the order becomes active.
             * @param endTime         The time at which the order becomes inactive.
             * @param revertOnInvalid A boolean indicating whether to revert if the
             *                        order is not active.
             *
             * @return valid A boolean indicating whether the order is active.
             */
            function _verifyTime(
                uint256 startTime,
                uint256 endTime,
                bool revertOnInvalid
            ) internal view returns (bool valid) {
                // Mark as valid if order has started and has not already ended.
                assembly {
                    valid := and(
                        iszero(gt(startTime, timestamp())),
                        gt(endTime, timestamp())
                    )
                }
                // Only revert on invalid if revertOnInvalid has been supplied as true.
                if (revertOnInvalid && !valid) {
                    _revertInvalidTime(startTime, endTime);
                }
            }
            /**
             * @dev Internal view function to verify the signature of an order. An
             *      ERC-1271 fallback will be attempted if either the signature length
             *      is not 64 or 65 bytes or if the recovered signer does not match the
             *      supplied offerer. Note that in cases where a 64 or 65 byte signature
             *      is supplied, only standard ECDSA signatures that recover to a
             *      non-zero address are supported.
             *
             * @param offerer   The offerer for the order.
             * @param orderHash The order hash.
             * @param signature A signature from the offerer indicating that the order
             *                  has been approved.
             */
            function _verifySignature(
                address offerer,
                bytes32 orderHash,
                bytes memory signature
            ) internal view {
                // Determine whether the offerer is the caller.
                bool offererIsCaller;
                assembly {
                    offererIsCaller := eq(offerer, caller())
                }
                // Skip signature verification if the offerer is the caller.
                if (offererIsCaller) {
                    return;
                }
                // Derive the EIP-712 domain separator.
                bytes32 domainSeparator = _domainSeparator();
                // Derive original EIP-712 digest using domain separator and order hash.
                bytes32 originalDigest = _deriveEIP712Digest(
                    domainSeparator,
                    orderHash
                );
                // Read the length of the signature from memory and place on the stack.
                uint256 originalSignatureLength = signature.length;
                // Determine effective digest if signature has a valid bulk order size.
                bytes32 digest;
                if (_isValidBulkOrderSize(originalSignatureLength)) {
                    // Rederive order hash and digest using bulk order proof.
                    (orderHash) = _computeBulkOrderProof(signature, orderHash);
                    digest = _deriveEIP712Digest(domainSeparator, orderHash);
                } else {
                    // Supply the original digest as the effective digest.
                    digest = originalDigest;
                }
                // Ensure that the signature for the digest is valid for the offerer.
                _assertValidSignature(
                    offerer,
                    digest,
                    originalDigest,
                    originalSignatureLength,
                    signature
                );
            }
            /**
             * @dev Determines whether the specified bulk order size is valid.
             *
             * @param signatureLength The signature length of the bulk order to check.
             *
             * @return validLength True if bulk order size is valid, false otherwise.
             */
            function _isValidBulkOrderSize(
                uint256 signatureLength
            ) internal pure returns (bool validLength) {
                // Utilize assembly to validate the length; the equivalent logic is
                // (64 + x) + 3 + 32y where (0 <= x <= 1) and (1 <= y <= 24).
                assembly {
                    validLength := and(
                        lt(
                            sub(signatureLength, BulkOrderProof_minSize),
                            BulkOrderProof_rangeSize
                        ),
                        lt(
                            and(
                                add(
                                    signatureLength,
                                    BulkOrderProof_lengthAdjustmentBeforeMask
                                ),
                                ThirtyOneBytes
                            ),
                            BulkOrderProof_lengthRangeAfterMask
                        )
                    )
                }
            }
            /**
             * @dev Computes the bulk order hash for the specified proof and leaf. Note
             *      that if an index that exceeds the number of orders in the bulk order
             *      payload will instead "wrap around" and refer to an earlier index.
             *
             * @param proofAndSignature The proof and signature of the bulk order.
             * @param leaf              The leaf of the bulk order tree.
             *
             * @return bulkOrderHash The bulk order hash.
             */
            function _computeBulkOrderProof(
                bytes memory proofAndSignature,
                bytes32 leaf
            ) internal pure returns (bytes32 bulkOrderHash) {
                // Declare arguments for the root hash and the height of the proof.
                bytes32 root;
                uint256 height;
                // Utilize assembly to efficiently derive the root hash using the proof.
                assembly {
                    // Retrieve the length of the proof, key, and signature combined.
                    let fullLength := mload(proofAndSignature)
                    // If proofAndSignature has odd length, it is a compact signature
                    // with 64 bytes.
                    let signatureLength := sub(ECDSA_MaxLength, and(fullLength, 1))
                    // Derive height (or depth of tree) with signature and proof length.
                    height := shr(OneWordShift, sub(fullLength, signatureLength))
                    // Update the length in memory to only include the signature.
                    mstore(proofAndSignature, signatureLength)
                    // Derive the pointer for the key using the signature length.
                    let keyPtr := add(proofAndSignature, add(OneWord, signatureLength))
                    // Retrieve the three-byte key using the derived pointer.
                    let key := shr(BulkOrderProof_keyShift, mload(keyPtr))
                    /// Retrieve pointer to first proof element by applying a constant
                    // for the key size to the derived key pointer.
                    let proof := add(keyPtr, BulkOrderProof_keySize)
                    // Compute level 1.
                    let scratchPtr1 := shl(OneWordShift, and(key, 1))
                    mstore(scratchPtr1, leaf)
                    mstore(xor(scratchPtr1, OneWord), mload(proof))
                    // Compute remaining proofs.
                    for {
                        let i := 1
                    } lt(i, height) {
                        i := add(i, 1)
                    } {
                        proof := add(proof, OneWord)
                        let scratchPtr := shl(OneWordShift, and(shr(i, key), 1))
                        mstore(scratchPtr, keccak256(0, TwoWords))
                        mstore(xor(scratchPtr, OneWord), mload(proof))
                    }
                    // Compute root hash.
                    root := keccak256(0, TwoWords)
                }
                // Retrieve appropriate typehash constant based on height.
                bytes32 rootTypeHash = _lookupBulkOrderTypehash(height);
                // Use the typehash and the root hash to derive final bulk order hash.
                assembly {
                    mstore(0, rootTypeHash)
                    mstore(OneWord, root)
                    bulkOrderHash := keccak256(0, TwoWords)
                }
            }
            /**
             * @dev Internal view function to validate that a given order is fillable
             *      and not cancelled based on the order status.
             *
             * @param orderHash       The order hash.
             * @param orderStatus     The status of the order, including whether it has
             *                        been cancelled and the fraction filled.
             * @param onlyAllowUnused A boolean flag indicating whether partial fills
             *                        are supported by the calling function.
             * @param revertOnInvalid A boolean indicating whether to revert if the
             *                        order has been cancelled or filled beyond the
             *                        allowable amount.
             *
             * @return valid A boolean indicating whether the order is valid.
             */
            function _verifyOrderStatus(
                bytes32 orderHash,
                OrderStatus storage orderStatus,
                bool onlyAllowUnused,
                bool revertOnInvalid
            ) internal view returns (bool valid) {
                // Ensure that the order has not been cancelled.
                if (orderStatus.isCancelled) {
                    // Only revert if revertOnInvalid has been supplied as true.
                    if (revertOnInvalid) {
                        _revertOrderIsCancelled(orderHash);
                    }
                    // Return false as the order status is invalid.
                    return false;
                }
                // Read order status numerator from storage and place on stack.
                uint256 orderStatusNumerator = orderStatus.numerator;
                // If the order is not entirely unused...
                if (orderStatusNumerator != 0) {
                    // ensure the order has not been partially filled when not allowed.
                    if (onlyAllowUnused) {
                        // Always revert on partial fills when onlyAllowUnused is true.
                        _revertOrderPartiallyFilled(orderHash);
                    }
                    // Otherwise, ensure that order has not been entirely filled.
                    else if (orderStatusNumerator >= orderStatus.denominator) {
                        // Only revert if revertOnInvalid has been supplied as true.
                        if (revertOnInvalid) {
                            _revertOrderAlreadyFilled(orderHash);
                        }
                        // Return false as the order status is invalid.
                        return false;
                    }
                }
                // Return true as the order status is valid.
                valid = true;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.14;
        import {
            BadReturnValueFromERC20OnTransfer_error_amount_ptr,
            BadReturnValueFromERC20OnTransfer_error_from_ptr,
            BadReturnValueFromERC20OnTransfer_error_length,
            BadReturnValueFromERC20OnTransfer_error_selector,
            BadReturnValueFromERC20OnTransfer_error_to_ptr,
            BadReturnValueFromERC20OnTransfer_error_token_ptr,
            BatchTransfer1155Params_amounts_head_ptr,
            BatchTransfer1155Params_calldata_baseSize,
            BatchTransfer1155Params_data_head_ptr,
            BatchTransfer1155Params_data_length_basePtr,
            BatchTransfer1155Params_ids_head_ptr,
            BatchTransfer1155Params_ids_length_offset,
            BatchTransfer1155Params_ids_length_ptr,
            BatchTransfer1155Params_ptr,
            ConduitBatch1155Transfer_amounts_length_baseOffset,
            ConduitBatch1155Transfer_from_offset,
            ConduitBatch1155Transfer_ids_head_offset,
            ConduitBatch1155Transfer_ids_length_offset,
            ConduitBatch1155Transfer_usable_head_size,
            ConduitBatchTransfer_amounts_head_offset,
            CostPerWord,
            DefaultFreeMemoryPointer,
            ERC1155_safeBatchTransferFrom_signature,
            ERC1155_safeTransferFrom_amount_ptr,
            ERC1155_safeTransferFrom_data_length_offset,
            ERC1155_safeTransferFrom_data_length_ptr,
            ERC1155_safeTransferFrom_data_offset_ptr,
            ERC1155_safeTransferFrom_from_ptr,
            ERC1155_safeTransferFrom_id_ptr,
            ERC1155_safeTransferFrom_length,
            ERC1155_safeTransferFrom_sig_ptr,
            ERC1155_safeTransferFrom_signature,
            ERC1155_safeTransferFrom_to_ptr,
            ERC1155BatchTransferGenericFailure_error_signature,
            ERC1155BatchTransferGenericFailure_ids_offset,
            ERC1155BatchTransferGenericFailure_token_ptr,
            ERC20_transferFrom_amount_ptr,
            ERC20_transferFrom_from_ptr,
            ERC20_transferFrom_length,
            ERC20_transferFrom_sig_ptr,
            ERC20_transferFrom_signature,
            ERC20_transferFrom_to_ptr,
            ERC721_transferFrom_from_ptr,
            ERC721_transferFrom_id_ptr,
            ERC721_transferFrom_length,
            ERC721_transferFrom_sig_ptr,
            ERC721_transferFrom_signature,
            ERC721_transferFrom_to_ptr,
            ExtraGasBuffer,
            FreeMemoryPointerSlot,
            Generic_error_selector_offset,
            Invalid1155BatchTransferEncoding_length,
            Invalid1155BatchTransferEncoding_ptr,
            Invalid1155BatchTransferEncoding_selector,
            MemoryExpansionCoefficientShift,
            NoContract_error_account_ptr,
            NoContract_error_length,
            NoContract_error_selector,
            OneWord,
            OneWordShift,
            Slot0x80,
            Slot0xA0,
            Slot0xC0,
            ThirtyOneBytes,
            TokenTransferGenericFailure_err_identifier_ptr,
            TokenTransferGenericFailure_error_amount_ptr,
            TokenTransferGenericFailure_error_from_ptr,
            TokenTransferGenericFailure_error_identifier_ptr,
            TokenTransferGenericFailure_error_length,
            TokenTransferGenericFailure_error_selector,
            TokenTransferGenericFailure_error_to_ptr,
            TokenTransferGenericFailure_error_token_ptr,
            TwoWords,
            TwoWordsShift,
            ZeroSlot
        } from "seaport-types/src/lib/TokenTransferrerConstants.sol";
        import {
            TokenTransferrerErrors
        } from "seaport-types/src/interfaces/TokenTransferrerErrors.sol";
        import {
            ConduitBatch1155Transfer
        } from "seaport-types/src/conduit/lib/ConduitStructs.sol";
        /**
         * @title TokenTransferrer
         * @author 0age
         * @custom:coauthor d1ll0n
         * @custom:coauthor transmissions11
         * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,
         *         ERC1155, and batch ERC1155 transfers, used by both Seaport as well as
         *         by conduits deployed by the ConduitController. Use great caution when
         *         considering these functions for use in other codebases, as there are
         *         significant side effects and edge cases that need to be thoroughly
         *         understood and carefully addressed.
         */
        contract TokenTransferrer is TokenTransferrerErrors {
            /**
             * @dev Internal function to transfer ERC20 tokens from a given originator
             *      to a given recipient. Sufficient approvals must be set on the
             *      contract performing the transfer.
             *
             * @param token      The ERC20 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param amount     The amount to transfer.
             */
            function _performERC20Transfer(
                address token,
                address from,
                address to,
                uint256 amount
            ) internal {
                // Utilize assembly to perform an optimized ERC20 token transfer.
                assembly {
                    // The free memory pointer memory slot will be used when populating
                    // call data for the transfer; read the value and restore it later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    // Write call data into memory, starting with function selector.
                    mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)
                    mstore(ERC20_transferFrom_from_ptr, from)
                    mstore(ERC20_transferFrom_to_ptr, to)
                    mstore(ERC20_transferFrom_amount_ptr, amount)
                    // Make call & copy up to 32 bytes of return data to scratch space.
                    // Scratch space does not need to be cleared ahead of time, as the
                    // subsequent check will ensure that either at least a full word of
                    // return data is received (in which case it will be overwritten) or
                    // that no data is received (in which case scratch space will be
                    // ignored) on a successful call to the given token.
                    let callStatus := call(
                        gas(),
                        token,
                        0,
                        ERC20_transferFrom_sig_ptr,
                        ERC20_transferFrom_length,
                        0,
                        OneWord
                    )
                    // Determine whether transfer was successful using status & result.
                    let success := and(
                        // Set success to whether the call reverted, if not check it
                        // either returned exactly 1 (can't just be non-zero data),
                        // or had no return data.
                        or(
                            and(eq(mload(0), 1), gt(returndatasize(), 31)),
                            iszero(returndatasize())
                        ),
                        callStatus
                    )
                    // Handle cases where either the transfer failed or no data was
                    // returned. Group these, as most transfers will succeed with data.
                    // Equivalent to `or(iszero(success), iszero(returndatasize()))`
                    // but after it's inverted for JUMPI this expression is cheaper.
                    if iszero(and(success, iszero(iszero(returndatasize())))) {
                        // If the token has no code or the transfer failed: Equivalent
                        // to `or(iszero(success), iszero(extcodesize(token)))` but
                        // after it's inverted for JUMPI this expression is cheaper.
                        if iszero(and(iszero(iszero(extcodesize(token))), success)) {
                            // If the transfer failed:
                            if iszero(success) {
                                // If it was due to a revert:
                                if iszero(callStatus) {
                                    // If it returned a message, bubble it up as long as
                                    // sufficient gas remains to do so:
                                    if returndatasize() {
                                        // Ensure that sufficient gas is available to
                                        // copy returndata while expanding memory where
                                        // necessary. Start by computing the word size
                                        // of returndata and allocated memory. Round up
                                        // to the nearest full word.
                                        let returnDataWords := shr(
                                            OneWordShift,
                                            add(returndatasize(), ThirtyOneBytes)
                                        )
                                        // Note: use the free memory pointer in place of
                                        // msize() to work around a Yul warning that
                                        // prevents accessing msize directly when the IR
                                        // pipeline is activated.
                                        let msizeWords := shr(OneWordShift, memPointer)
                                        // Next, compute the cost of the returndatacopy.
                                        let cost := mul(CostPerWord, returnDataWords)
                                        // Then, compute cost of new memory allocation.
                                        if gt(returnDataWords, msizeWords) {
                                            cost := add(
                                                cost,
                                                add(
                                                    mul(
                                                        sub(
                                                            returnDataWords,
                                                            msizeWords
                                                        ),
                                                        CostPerWord
                                                    ),
                                                    shr(
                                                        MemoryExpansionCoefficientShift,
                                                        sub(
                                                            mul(
                                                                returnDataWords,
                                                                returnDataWords
                                                            ),
                                                            mul(msizeWords, msizeWords)
                                                        )
                                                    )
                                                )
                                            )
                                        }
                                        // Finally, add a small constant and compare to
                                        // gas remaining; bubble up the revert data if
                                        // enough gas is still available.
                                        if lt(add(cost, ExtraGasBuffer), gas()) {
                                            // Copy returndata to memory; overwrite
                                            // existing memory.
                                            returndatacopy(0, 0, returndatasize())
                                            // Revert, specifying memory region with
                                            // copied returndata.
                                            revert(0, returndatasize())
                                        }
                                    }
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(
                                        0,
                                        TokenTransferGenericFailure_error_selector
                                    )
                                    mstore(
                                        TokenTransferGenericFailure_error_token_ptr,
                                        token
                                    )
                                    mstore(
                                        TokenTransferGenericFailure_error_from_ptr,
                                        from
                                    )
                                    mstore(TokenTransferGenericFailure_error_to_ptr, to)
                                    mstore(
                                        TokenTransferGenericFailure_err_identifier_ptr,
                                        0
                                    )
                                    mstore(
                                        TokenTransferGenericFailure_error_amount_ptr,
                                        amount
                                    )
                                    // revert(abi.encodeWithSignature(
                                    //     "TokenTransferGenericFailure(
                                    //         address,address,address,uint256,uint256
                                    //     )", token, from, to, identifier, amount
                                    // ))
                                    revert(
                                        Generic_error_selector_offset,
                                        TokenTransferGenericFailure_error_length
                                    )
                                }
                                // Otherwise revert with a message about the token
                                // returning false or non-compliant return values.
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(
                                    0,
                                    BadReturnValueFromERC20OnTransfer_error_selector
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_token_ptr,
                                    token
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_from_ptr,
                                    from
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_to_ptr,
                                    to
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_amount_ptr,
                                    amount
                                )
                                // revert(abi.encodeWithSignature(
                                //     "BadReturnValueFromERC20OnTransfer(
                                //         address,address,address,uint256
                                //     )", token, from, to, amount
                                // ))
                                revert(
                                    Generic_error_selector_offset,
                                    BadReturnValueFromERC20OnTransfer_error_length
                                )
                            }
                            // Otherwise, revert with error about token not having code:
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, NoContract_error_selector)
                            mstore(NoContract_error_account_ptr, token)
                            // revert(abi.encodeWithSignature(
                            //      "NoContract(address)", account
                            // ))
                            revert(
                                Generic_error_selector_offset,
                                NoContract_error_length
                            )
                        }
                        // Otherwise, the token just returned no data despite the call
                        // having succeeded; no need to optimize for this as it's not
                        // technically ERC20 compliant.
                    }
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer an ERC721 token from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer. Note that this function does
             *      not check whether the receiver can accept the ERC721 token (i.e. it
             *      does not use `safeTransferFrom`).
             *
             * @param token      The ERC721 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param identifier The tokenId to transfer.
             */
            function _performERC721Transfer(
                address token,
                address from,
                address to,
                uint256 identifier
            ) internal {
                // Utilize assembly to perform an optimized ERC721 token transfer.
                assembly {
                    // If the token has no code, revert.
                    if iszero(extcodesize(token)) {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, NoContract_error_selector)
                        mstore(NoContract_error_account_ptr, token)
                        // revert(abi.encodeWithSignature(
                        //     "NoContract(address)", account
                        // ))
                        revert(Generic_error_selector_offset, NoContract_error_length)
                    }
                    // The free memory pointer memory slot will be used when populating
                    // call data for the transfer; read the value and restore it later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    // Write call data to memory starting with function selector.
                    mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)
                    mstore(ERC721_transferFrom_from_ptr, from)
                    mstore(ERC721_transferFrom_to_ptr, to)
                    mstore(ERC721_transferFrom_id_ptr, identifier)
                    // Perform the call, ignoring return data.
                    let success := call(
                        gas(),
                        token,
                        0,
                        ERC721_transferFrom_sig_ptr,
                        ERC721_transferFrom_length,
                        0,
                        0
                    )
                    // If the transfer reverted:
                    if iszero(success) {
                        // If it returned a message, bubble it up as long as sufficient
                        // gas remains to do so:
                        if returndatasize() {
                            // Ensure that sufficient gas is available to copy
                            // returndata while expanding memory where necessary. Start
                            // by computing word size of returndata & allocated memory.
                            // Round up to the nearest full word.
                            let returnDataWords := shr(
                                OneWordShift,
                                add(returndatasize(), ThirtyOneBytes)
                            )
                            // Note: use the free memory pointer in place of msize() to
                            // work around a Yul warning that prevents accessing msize
                            // directly when the IR pipeline is activated.
                            let msizeWords := shr(OneWordShift, memPointer)
                            // Next, compute the cost of the returndatacopy.
                            let cost := mul(CostPerWord, returnDataWords)
                            // Then, compute cost of new memory allocation.
                            if gt(returnDataWords, msizeWords) {
                                cost := add(
                                    cost,
                                    add(
                                        mul(
                                            sub(returnDataWords, msizeWords),
                                            CostPerWord
                                        ),
                                        shr(
                                            MemoryExpansionCoefficientShift,
                                            sub(
                                                mul(returnDataWords, returnDataWords),
                                                mul(msizeWords, msizeWords)
                                            )
                                        )
                                    )
                                )
                            }
                            // Finally, add a small constant and compare to gas
                            // remaining; bubble up the revert data if enough gas is
                            // still available.
                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                // Copy returndata to memory; overwrite existing memory.
                                returndatacopy(0, 0, returndatasize())
                                // Revert, giving memory region with copied returndata.
                                revert(0, returndatasize())
                            }
                        }
                        // Otherwise revert with a generic error message.
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, TokenTransferGenericFailure_error_selector)
                        mstore(TokenTransferGenericFailure_error_token_ptr, token)
                        mstore(TokenTransferGenericFailure_error_from_ptr, from)
                        mstore(TokenTransferGenericFailure_error_to_ptr, to)
                        mstore(
                            TokenTransferGenericFailure_error_identifier_ptr,
                            identifier
                        )
                        mstore(TokenTransferGenericFailure_error_amount_ptr, 1)
                        // revert(abi.encodeWithSignature(
                        //     "TokenTransferGenericFailure(
                        //         address,address,address,uint256,uint256
                        //     )", token, from, to, identifier, amount
                        // ))
                        revert(
                            Generic_error_selector_offset,
                            TokenTransferGenericFailure_error_length
                        )
                    }
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer ERC1155 tokens from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer and contract recipients must
             *      implement the ERC1155TokenReceiver interface to indicate that they
             *      are willing to accept the transfer.
             *
             * @param token      The ERC1155 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param identifier The id to transfer.
             * @param amount     The amount to transfer.
             */
            function _performERC1155Transfer(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount
            ) internal {
                // Utilize assembly to perform an optimized ERC1155 token transfer.
                assembly {
                    // If the token has no code, revert.
                    if iszero(extcodesize(token)) {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, NoContract_error_selector)
                        mstore(NoContract_error_account_ptr, token)
                        // revert(abi.encodeWithSignature(
                        //     "NoContract(address)", account
                        // ))
                        revert(Generic_error_selector_offset, NoContract_error_length)
                    }
                    // The following memory slots will be used when populating call data
                    // for the transfer; read the values and restore them later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    let slot0x80 := mload(Slot0x80)
                    let slot0xA0 := mload(Slot0xA0)
                    let slot0xC0 := mload(Slot0xC0)
                    // Write call data into memory, beginning with function selector.
                    mstore(
                        ERC1155_safeTransferFrom_sig_ptr,
                        ERC1155_safeTransferFrom_signature
                    )
                    mstore(ERC1155_safeTransferFrom_from_ptr, from)
                    mstore(ERC1155_safeTransferFrom_to_ptr, to)
                    mstore(ERC1155_safeTransferFrom_id_ptr, identifier)
                    mstore(ERC1155_safeTransferFrom_amount_ptr, amount)
                    mstore(
                        ERC1155_safeTransferFrom_data_offset_ptr,
                        ERC1155_safeTransferFrom_data_length_offset
                    )
                    mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)
                    // Perform the call, ignoring return data.
                    let success := call(
                        gas(),
                        token,
                        0,
                        ERC1155_safeTransferFrom_sig_ptr,
                        ERC1155_safeTransferFrom_length,
                        0,
                        0
                    )
                    // If the transfer reverted:
                    if iszero(success) {
                        // If it returned a message, bubble it up as long as sufficient
                        // gas remains to do so:
                        if returndatasize() {
                            // Ensure that sufficient gas is available to copy
                            // returndata while expanding memory where necessary. Start
                            // by computing word size of returndata & allocated memory.
                            // Round up to the nearest full word.
                            let returnDataWords := shr(
                                OneWordShift,
                                add(returndatasize(), ThirtyOneBytes)
                            )
                            // Note: use the free memory pointer in place of msize() to
                            // work around a Yul warning that prevents accessing msize
                            // directly when the IR pipeline is activated.
                            let msizeWords := shr(OneWordShift, memPointer)
                            // Next, compute the cost of the returndatacopy.
                            let cost := mul(CostPerWord, returnDataWords)
                            // Then, compute cost of new memory allocation.
                            if gt(returnDataWords, msizeWords) {
                                cost := add(
                                    cost,
                                    add(
                                        mul(
                                            sub(returnDataWords, msizeWords),
                                            CostPerWord
                                        ),
                                        shr(
                                            MemoryExpansionCoefficientShift,
                                            sub(
                                                mul(returnDataWords, returnDataWords),
                                                mul(msizeWords, msizeWords)
                                            )
                                        )
                                    )
                                )
                            }
                            // Finally, add a small constant and compare to gas
                            // remaining; bubble up the revert data if enough gas is
                            // still available.
                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                // Copy returndata to memory; overwrite existing memory.
                                returndatacopy(0, 0, returndatasize())
                                // Revert, giving memory region with copied returndata.
                                revert(0, returndatasize())
                            }
                        }
                        // Otherwise revert with a generic error message.
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, TokenTransferGenericFailure_error_selector)
                        mstore(TokenTransferGenericFailure_error_token_ptr, token)
                        mstore(TokenTransferGenericFailure_error_from_ptr, from)
                        mstore(TokenTransferGenericFailure_error_to_ptr, to)
                        mstore(
                            TokenTransferGenericFailure_error_identifier_ptr,
                            identifier
                        )
                        mstore(TokenTransferGenericFailure_error_amount_ptr, amount)
                        // revert(abi.encodeWithSignature(
                        //     "TokenTransferGenericFailure(
                        //         address,address,address,uint256,uint256
                        //     )", token, from, to, identifier, amount
                        // ))
                        revert(
                            Generic_error_selector_offset,
                            TokenTransferGenericFailure_error_length
                        )
                    }
                    mstore(Slot0x80, slot0x80) // Restore slot 0x80.
                    mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.
                    mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer ERC1155 tokens from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer and contract recipients must
             *      implement the ERC1155TokenReceiver interface to indicate that they
             *      are willing to accept the transfer. NOTE: this function is not
             *      memory-safe; it will overwrite existing memory, restore the free
             *      memory pointer to the default value, and overwrite the zero slot.
             *      This function should only be called once memory is no longer
             *      required and when uninitialized arrays are not utilized, and memory
             *      should be considered fully corrupted (aside from the existence of a
             *      default-value free memory pointer) after calling this function.
             *
             * @param batchTransfers The group of 1155 batch transfers to perform.
             */
            function _performERC1155BatchTransfers(
                ConduitBatch1155Transfer[] calldata batchTransfers
            ) internal {
                // Utilize assembly to perform optimized batch 1155 transfers.
                assembly {
                    let len := batchTransfers.length
                    // Pointer to first head in the array, which is offset to the struct
                    // at each index. This gets incremented after each loop to avoid
                    // multiplying by 32 to get the offset for each element.
                    let nextElementHeadPtr := batchTransfers.offset
                    // Pointer to beginning of the head of the array. This is the
                    // reference position each offset references. It's held static to
                    // let each loop calculate the data position for an element.
                    let arrayHeadPtr := nextElementHeadPtr
                    // Write the function selector, which will be reused for each call:
                    // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)
                    mstore(
                        ConduitBatch1155Transfer_from_offset,
                        ERC1155_safeBatchTransferFrom_signature
                    )
                    // Iterate over each batch transfer.
                    for {
                        let i := 0
                    } lt(i, len) {
                        i := add(i, 1)
                    } {
                        // Read the offset to the beginning of the element and add
                        // it to pointer to the beginning of the array head to get
                        // the absolute position of the element in calldata.
                        let elementPtr := add(
                            arrayHeadPtr,
                            calldataload(nextElementHeadPtr)
                        )
                        // Retrieve the token from calldata.
                        let token := calldataload(elementPtr)
                        // If the token has no code, revert.
                        if iszero(extcodesize(token)) {
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, NoContract_error_selector)
                            mstore(NoContract_error_account_ptr, token)
                            // revert(abi.encodeWithSignature(
                            //     "NoContract(address)", account
                            // ))
                            revert(
                                Generic_error_selector_offset,
                                NoContract_error_length
                            )
                        }
                        // Get the total number of supplied ids.
                        let idsLength := calldataload(
                            add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)
                        )
                        // Determine the expected offset for the amounts array.
                        let expectedAmountsOffset := add(
                            ConduitBatch1155Transfer_amounts_length_baseOffset,
                            shl(OneWordShift, idsLength)
                        )
                        // Validate struct encoding.
                        let invalidEncoding := iszero(
                            and(
                                // ids.length == amounts.length
                                eq(
                                    idsLength,
                                    calldataload(add(elementPtr, expectedAmountsOffset))
                                ),
                                and(
                                    // ids_offset == 0xa0
                                    eq(
                                        calldataload(
                                            add(
                                                elementPtr,
                                                ConduitBatch1155Transfer_ids_head_offset
                                            )
                                        ),
                                        ConduitBatch1155Transfer_ids_length_offset
                                    ),
                                    // amounts_offset == 0xc0 + ids.length*32
                                    eq(
                                        calldataload(
                                            add(
                                                elementPtr,
                                                ConduitBatchTransfer_amounts_head_offset
                                            )
                                        ),
                                        expectedAmountsOffset
                                    )
                                )
                            )
                        )
                        // Revert with an error if the encoding is not valid.
                        if invalidEncoding {
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(
                                Invalid1155BatchTransferEncoding_ptr,
                                Invalid1155BatchTransferEncoding_selector
                            )
                            // revert(abi.encodeWithSignature(
                            //     "Invalid1155BatchTransferEncoding()"
                            // ))
                            revert(
                                Invalid1155BatchTransferEncoding_ptr,
                                Invalid1155BatchTransferEncoding_length
                            )
                        }
                        // Update the offset position for the next loop
                        nextElementHeadPtr := add(nextElementHeadPtr, OneWord)
                        // Copy the first section of calldata (before dynamic values).
                        calldatacopy(
                            BatchTransfer1155Params_ptr,
                            add(elementPtr, ConduitBatch1155Transfer_from_offset),
                            ConduitBatch1155Transfer_usable_head_size
                        )
                        // Determine size of calldata required for ids and amounts. Note
                        // that the size includes both lengths as well as the data.
                        let idsAndAmountsSize := add(
                            TwoWords,
                            shl(TwoWordsShift, idsLength)
                        )
                        // Update the offset for the data array in memory.
                        mstore(
                            BatchTransfer1155Params_data_head_ptr,
                            add(
                                BatchTransfer1155Params_ids_length_offset,
                                idsAndAmountsSize
                            )
                        )
                        // Set the length of the data array in memory to zero.
                        mstore(
                            add(
                                BatchTransfer1155Params_data_length_basePtr,
                                idsAndAmountsSize
                            ),
                            0
                        )
                        // Determine the total calldata size for the call to transfer.
                        let transferDataSize := add(
                            BatchTransfer1155Params_calldata_baseSize,
                            idsAndAmountsSize
                        )
                        // Copy second section of calldata (including dynamic values).
                        calldatacopy(
                            BatchTransfer1155Params_ids_length_ptr,
                            add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),
                            idsAndAmountsSize
                        )
                        // Perform the call to transfer 1155 tokens.
                        let success := call(
                            gas(),
                            token,
                            0,
                            ConduitBatch1155Transfer_from_offset, // Data start.
                            transferDataSize, // Location of the length of callData.
                            0,
                            0
                        )
                        // If the transfer reverted:
                        if iszero(success) {
                            // If it returned a message, bubble it up as long as
                            // sufficient gas remains to do so:
                            if returndatasize() {
                                // Ensure that sufficient gas is available to copy
                                // returndata while expanding memory where necessary.
                                // Start by computing word size of returndata and
                                // allocated memory. Round up to the nearest full word.
                                let returnDataWords := shr(
                                    OneWordShift,
                                    add(returndatasize(), ThirtyOneBytes)
                                )
                                // Note: use transferDataSize in place of msize() to
                                // work around a Yul warning that prevents accessing
                                // msize directly when the IR pipeline is activated.
                                // The free memory pointer is not used here because
                                // this function does almost all memory management
                                // manually and does not update it, and transferDataSize
                                // should be the largest memory value used (unless a
                                // previous batch was larger).
                                let msizeWords := shr(OneWordShift, transferDataSize)
                                // Next, compute the cost of the returndatacopy.
                                let cost := mul(CostPerWord, returnDataWords)
                                // Then, compute cost of new memory allocation.
                                if gt(returnDataWords, msizeWords) {
                                    cost := add(
                                        cost,
                                        add(
                                            mul(
                                                sub(returnDataWords, msizeWords),
                                                CostPerWord
                                            ),
                                            shr(
                                                MemoryExpansionCoefficientShift,
                                                sub(
                                                    mul(
                                                        returnDataWords,
                                                        returnDataWords
                                                    ),
                                                    mul(msizeWords, msizeWords)
                                                )
                                            )
                                        )
                                    )
                                }
                                // Finally, add a small constant and compare to gas
                                // remaining; bubble up the revert data if enough gas is
                                // still available.
                                if lt(add(cost, ExtraGasBuffer), gas()) {
                                    // Copy returndata to memory; overwrite existing.
                                    returndatacopy(0, 0, returndatasize())
                                    // Revert with memory region containing returndata.
                                    revert(0, returndatasize())
                                }
                            }
                            // Set the error signature.
                            mstore(
                                0,
                                ERC1155BatchTransferGenericFailure_error_signature
                            )
                            // Write the token.
                            mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)
                            // Increase the offset to ids by 32.
                            mstore(
                                BatchTransfer1155Params_ids_head_ptr,
                                ERC1155BatchTransferGenericFailure_ids_offset
                            )
                            // Increase the offset to amounts by 32.
                            mstore(
                                BatchTransfer1155Params_amounts_head_ptr,
                                add(
                                    OneWord,
                                    mload(BatchTransfer1155Params_amounts_head_ptr)
                                )
                            )
                            // Return modified region. The total size stays the same as
                            // `token` uses the same number of bytes as `data.length`.
                            revert(0, transferDataSize)
                        }
                    }
                    // Reset the free memory pointer to the default value; memory must
                    // be assumed to be dirtied and not reused from this point forward.
                    // Also note that the zero slot is not reset to zero, meaning empty
                    // arrays cannot be safely created or utilized until it is restored.
                    mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title ZoneInteractionErrors
         * @author 0age
         * @notice ZoneInteractionErrors contains errors related to zone interaction.
         */
        interface ZoneInteractionErrors {
            /**
             * @dev Revert with an error when attempting to fill an order that specifies
             *      a restricted submitter as its order type when not submitted by
             *      either the offerer or the order's zone or approved as valid by the
             *      zone in question via a call to `isValidOrder`.
             *
             * @param orderHash The order hash for the invalid restricted order.
             */
            error InvalidRestrictedOrder(bytes32 orderHash);
            /**
             * @dev Revert with an error when attempting to fill a contract order that
             *      fails to generate an order successfully, that does not adhere to the
             *      requirements for minimum spent or maximum received supplied by the
             *      fulfiller, or that fails the post-execution `ratifyOrder` check..
             *
             * @param orderHash The order hash for the invalid contract order.
             */
            error InvalidContractOrder(bytes32 orderHash);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            CostPerWord,
            ExtraGasBuffer,
            FreeMemoryPointerSlot,
            MemoryExpansionCoefficientShift,
            OneWord,
            OneWordShift,
            ThirtyOneBytes
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            MemoryPointer,
            MemoryPointerLib
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        import {
            AdvancedOrder,
            Execution
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        /**
         * @title LowLevelHelpers
         * @author 0age
         * @notice LowLevelHelpers contains logic for performing various low-level
         *         operations.
         */
        contract LowLevelHelpers {
            /**
             * @dev Internal view function to revert and pass along the revert reason if
             *      data was returned by the last call and that the size of that data
             *      does not exceed the currently allocated memory size.
             */
            function _revertWithReasonIfOneIsReturned() internal view {
                assembly {
                    // If it returned a message, bubble it up as long as sufficient gas
                    // remains to do so:
                    if returndatasize() {
                        // Ensure that sufficient gas is available to copy returndata
                        // while expanding memory where necessary. Start by computing
                        // the word size of returndata and allocated memory.
                        let returnDataWords := shr(
                            OneWordShift,
                            add(returndatasize(), ThirtyOneBytes)
                        )
                        // Note: use the free memory pointer in place of msize() to work
                        // around a Yul warning that prevents accessing msize directly
                        // when the IR pipeline is activated.
                        let msizeWords := shr(
                            OneWordShift,
                            mload(FreeMemoryPointerSlot)
                        )
                        // Next, compute the cost of the returndatacopy.
                        let cost := mul(CostPerWord, returnDataWords)
                        // Then, compute cost of new memory allocation.
                        if gt(returnDataWords, msizeWords) {
                            cost := add(
                                cost,
                                add(
                                    mul(sub(returnDataWords, msizeWords), CostPerWord),
                                    shr(
                                        MemoryExpansionCoefficientShift,
                                        sub(
                                            mul(returnDataWords, returnDataWords),
                                            mul(msizeWords, msizeWords)
                                        )
                                    )
                                )
                            )
                        }
                        // Finally, add a small constant and compare to gas remaining;
                        // bubble up the revert data if enough gas is still available.
                        if lt(add(cost, ExtraGasBuffer), gas()) {
                            // Copy returndata to memory; overwrite existing memory.
                            returndatacopy(0, 0, returndatasize())
                            // Revert, specifying memory region with copied returndata.
                            revert(0, returndatasize())
                        }
                    }
                }
            }
            /**
             * @dev Internal view function to branchlessly select either the caller (if
             *      a supplied recipient is equal to zero) or the supplied recipient (if
             *      that recipient is a nonzero value).
             *
             * @param recipient The supplied recipient.
             *
             * @return updatedRecipient The updated recipient.
             */
            function _substituteCallerForEmptyRecipient(
                address recipient
            ) internal view returns (address updatedRecipient) {
                // Utilize assembly to perform a branchless operation on the recipient.
                assembly {
                    // Add caller to recipient if recipient equals 0; otherwise add 0.
                    updatedRecipient := add(recipient, mul(iszero(recipient), caller()))
                }
            }
            /**
             * @dev Internal pure function to cast a `bool` value to a `uint256` value.
             *
             * @param b The `bool` value to cast.
             *
             * @return u The `uint256` value.
             */
            function _cast(bool b) internal pure returns (uint256 u) {
                assembly {
                    u := b
                }
            }
            /**
             * @dev Internal pure function to cast the `pptrOffset` function from
             *      `MemoryPointerLib` to a function that takes a memory array of
             *      `AdvancedOrder` and an offset in memory and returns the
             *      `AdvancedOrder` whose pointer is stored at that offset from the
             *      array length.
             */
            function _getReadAdvancedOrderByOffset()
                internal
                pure
                returns (
                    function(AdvancedOrder[] memory, uint256)
                        internal
                        pure
                        returns (AdvancedOrder memory) fn2
                )
            {
                function(MemoryPointer, uint256)
                    internal
                    pure
                    returns (MemoryPointer) fn1 = MemoryPointerLib.pptrOffset;
                assembly {
                    fn2 := fn1
                }
            }
            /**
             * @dev Internal pure function to cast the `pptrOffset` function from
             *      `MemoryPointerLib` to a function that takes a memory array of
             *      `Execution` and an offset in memory and returns the
             *      `Execution` whose pointer is stored at that offset from the
             *      array length.
             */
            function _getReadExecutionByOffset()
                internal
                pure
                returns (
                    function(Execution[] memory, uint256)
                        internal
                        pure
                        returns (Execution memory) fn2
                )
            {
                function(MemoryPointer, uint256)
                    internal
                    pure
                    returns (MemoryPointer) fn1 = MemoryPointerLib.pptrOffset;
                assembly {
                    fn2 := fn1
                }
            }
            /**
             * @dev Internal pure function to return a `true` value that solc
             *      will not recognize as a compile time constant.
             *
             *      This function is used to bypass function specialization for
             *      functions which take a constant boolean as an input parameter.
             *
             *      This should only be used in cases where specialization has a
             *      negligible impact on the gas cost of the function.
             *
             *      Note: assumes the calldatasize is non-zero.
             */
            function _runTimeConstantTrue() internal pure returns (bool) {
                return msg.data.length > 0;
            }
            /**
             * @dev Internal pure function to return a `false` value that solc
             *      will not recognize as a compile time constant.
             *
             *      This function is used to bypass function specialization for
             *      functions which take a constant boolean as an input parameter.
             *
             *      This should only be used in cases where specialization has a
             *      negligible impact on the gas cost of the function.
             *
             *      Note: assumes the calldatasize is non-zero.
             */
            function _runTimeConstantFalse() internal pure returns (bool) {
                return msg.data.length == 0;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            authorizeOrder_calldata_baseOffset,
            authorizeOrder_head_offset,
            authorizeOrder_selector_offset,
            authorizeOrder_selector,
            authorizeOrder_zoneParameters_offset,
            BasicOrder_addlRecipients_length_cdPtr,
            BasicOrder_common_params_size,
            BasicOrder_consideration_offset_from_offer,
            BasicOrder_offerer_cdPtr,
            BasicOrder_startTime_cdPtr,
            BasicOrder_startTimeThroughZoneHash_size,
            BasicOrder_totalOriginalAdditionalRecipients_cdPtr,
            Common_amount_offset,
            Common_identifier_offset,
            Common_token_offset,
            generateOrder_base_tail_offset,
            generateOrder_context_head_offset,
            generateOrder_head_offset,
            generateOrder_maximumSpent_head_offset,
            generateOrder_minimumReceived_head_offset,
            generateOrder_selector_offset,
            generateOrder_selector,
            OneWord,
            OneWordShift,
            OnlyFullWordMask,
            OrderFulfilled_baseDataSize,
            OrderFulfilled_offer_length_baseOffset,
            OrderParameters_consideration_head_offset,
            OrderParameters_endTime_offset,
            OrderParameters_offer_head_offset,
            OrderParameters_startTime_offset,
            OrderParameters_zoneHash_offset,
            ratifyOrder_base_tail_offset,
            ratifyOrder_consideration_head_offset,
            ratifyOrder_context_head_offset,
            ratifyOrder_contractNonce_offset,
            ratifyOrder_head_offset,
            ratifyOrder_orderHashes_head_offset,
            ratifyOrder_selector_offset,
            ratifyOrder_selector,
            ReceivedItem_size,
            Selector_length,
            SixtyThreeBytes,
            SpentItem_size_shift,
            SpentItem_size,
            validateOrder_selector,
            validateOrder_selector_offset,
            ZoneParameters_base_tail_offset,
            ZoneParameters_basicOrderFixedElements_length,
            ZoneParameters_consideration_head_offset,
            ZoneParameters_endTime_offset,
            ZoneParameters_extraData_head_offset,
            ZoneParameters_fulfiller_offset,
            ZoneParameters_offer_head_offset,
            ZoneParameters_offerer_offset,
            ZoneParameters_orderHashes_head_offset,
            ZoneParameters_selectorAndPointer_length,
            ZoneParameters_startTime_offset,
            ZoneParameters_zoneHash_offset
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            BasicOrderParameters,
            OrderParameters
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            CalldataPointer,
            getFreeMemoryPointer,
            setFreeMemoryPointer,
            MemoryPointer,
            OffsetOrLengthMask
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        contract ConsiderationEncoder {
            /**
             * @dev Takes a bytes array and casts it to a memory pointer.
             *
             * @param obj A bytes array in memory.
             *
             * @return ptr A memory pointer to the start of the bytes array in memory.
             */
            function toMemoryPointer(
                bytes memory obj
            ) internal pure returns (MemoryPointer ptr) {
                assembly {
                    ptr := obj
                }
            }
            /**
             * @dev Takes an array of bytes32 types and casts it to a memory pointer.
             *
             * @param obj An array of bytes32 types in memory.
             *
             * @return ptr A memory pointer to the start of the array of bytes32 types
             *             in memory.
             */
            function toMemoryPointer(
                bytes32[] memory obj
            ) internal pure returns (MemoryPointer ptr) {
                assembly {
                    ptr := obj
                }
            }
            /**
             * @dev Takes a bytes array in memory and copies it to a new location in
             *      memory.
             *
             * @param src A memory pointer referencing the bytes array to be copied (and
             *            pointing to the length of the bytes array).
             * @param src A memory pointer referencing the location in memory to copy
             *            the bytes array to (and pointing to the length of the copied
             *            bytes array).
             *
             * @return size The size of the bytes array.
             */
            function _encodeBytes(
                MemoryPointer src,
                MemoryPointer dst
            ) internal view returns (uint256 size) {
                unchecked {
                    // Mask the length of the bytes array to protect against overflow
                    // and round up to the nearest word.
                    // Note: `size` also includes the 1 word that stores the length.
                    size = (src.readUint256() + SixtyThreeBytes) & OnlyFullWordMask;
                    // Copy the bytes array to the new memory location.
                    src.copy(dst, size);
                }
            }
            /**
             * @dev Takes an OrderParameters struct and a context bytes array in memory
             *      and encodes it as `generateOrder` calldata.
             *
             * @param orderParameters The OrderParameters struct used to construct the
             *                        encoded `generateOrder` calldata.
             * @param context         The context bytes array used to construct the
             *                        encoded `generateOrder` calldata.
             *
             * @return dst  A memory pointer referencing the encoded `generateOrder`
             *              calldata.
             * @return size The size of the bytes array.
             */
            function _encodeGenerateOrder(
                OrderParameters memory orderParameters,
                bytes memory context
            ) internal view returns (MemoryPointer dst, uint256 size) {
                // Get the memory pointer for the OrderParameters struct.
                MemoryPointer src = orderParameters.toMemoryPointer();
                // Get free memory pointer to write calldata to.
                dst = getFreeMemoryPointer();
                // Write generateOrder selector and get pointer to start of calldata.
                dst.write(generateOrder_selector);
                dst = dst.offset(generateOrder_selector_offset);
                // Get pointer to the beginning of the encoded data.
                MemoryPointer dstHead = dst.offset(generateOrder_head_offset);
                // Write `fulfiller` to calldata.
                dstHead.write(msg.sender);
                // Initialize tail offset, used to populate the minimumReceived array.
                uint256 tailOffset = generateOrder_base_tail_offset;
                // Write offset to minimumReceived.
                dstHead.offset(generateOrder_minimumReceived_head_offset).write(
                    tailOffset
                );
                // Get memory pointer to `orderParameters.offer.length`.
                MemoryPointer srcOfferPointer = src
                    .offset(OrderParameters_offer_head_offset)
                    .readMemoryPointer();
                // Encode the offer array as a `SpentItem[]`.
                uint256 minimumReceivedSize = _encodeSpentItems(
                    srcOfferPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate maximumSpent array.
                    tailOffset += minimumReceivedSize;
                }
                // Write offset to maximumSpent.
                dstHead.offset(generateOrder_maximumSpent_head_offset).write(
                    tailOffset
                );
                // Get memory pointer to `orderParameters.consideration.length`.
                MemoryPointer srcConsiderationPointer = src
                    .offset(OrderParameters_consideration_head_offset)
                    .readMemoryPointer();
                // Encode the consideration array as a `SpentItem[]`.
                uint256 maximumSpentSize = _encodeSpentItems(
                    srcConsiderationPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate context array.
                    tailOffset += maximumSpentSize;
                }
                // Write offset to context.
                dstHead.offset(generateOrder_context_head_offset).write(tailOffset);
                // Get memory pointer to context.
                MemoryPointer srcContext = toMemoryPointer(context);
                // Encode context as a bytes array.
                uint256 contextSize = _encodeBytes(
                    srcContext,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment the tail offset, now used to determine final size.
                    tailOffset += contextSize;
                    // Derive the final size by including the selector.
                    size = Selector_length + tailOffset;
                }
            }
            /**
             * @dev Takes an order hash (e.g. offerer shifted 96 bits to the left XOR'd
             *      with the contract nonce in the case of contract orders), an
             *      OrderParameters struct, context bytes array, and an array of order
             *      hashes for each order included as part of the current fulfillment
             *      and encodes it as `ratifyOrder` calldata.
             *
             * @param orderHash       The order hash (e.g. shl(0x60, offerer) ^ nonce).
             * @param orderParameters The OrderParameters struct used to construct the
             *                        encoded `ratifyOrder` calldata.
             * @param context         The context bytes array used to construct the
             *                        encoded `ratifyOrder` calldata.
             * @param orderHashes     An array of bytes32 values representing the order
             *                        hashes of all orders included as part of the
             *                        current fulfillment.
             * @param shiftedOfferer  The offerer for the order, shifted 96 bits to the
             *                        left.
             *
             * @return dst  A memory pointer referencing the encoded `ratifyOrder`
             *              calldata.
             * @return size The size of the bytes array.
             */
            function _encodeRatifyOrder(
                bytes32 orderHash, // e.g. shl(0x60, offerer) ^ contract nonce
                OrderParameters memory orderParameters,
                bytes memory context, // encoded based on the schemaID
                bytes32[] memory orderHashes,
                uint256 shiftedOfferer
            ) internal view returns (MemoryPointer dst, uint256 size) {
                // Get free memory pointer to write calldata to. This isn't allocated as
                // it is only used for a single function call.
                dst = getFreeMemoryPointer();
                // Write ratifyOrder selector and get pointer to start of calldata.
                dst.write(ratifyOrder_selector);
                dst = dst.offset(ratifyOrder_selector_offset);
                // Get pointer to the beginning of the encoded data.
                MemoryPointer dstHead = dst.offset(ratifyOrder_head_offset);
                // Write contractNonce to calldata via xor(orderHash, shiftedOfferer).
                dstHead.offset(ratifyOrder_contractNonce_offset).write(
                    uint256(orderHash) ^ shiftedOfferer
                );
                // Initialize tail offset, used to populate the offer array.
                uint256 tailOffset = ratifyOrder_base_tail_offset;
                MemoryPointer src = orderParameters.toMemoryPointer();
                // Write offset to `offer`.
                dstHead.write(tailOffset);
                // Get memory pointer to `orderParameters.offer.length`.
                MemoryPointer srcOfferPointer = src
                    .offset(OrderParameters_offer_head_offset)
                    .readMemoryPointer();
                // Encode the offer array as a `SpentItem[]`.
                uint256 offerSize = _encodeSpentItems(
                    srcOfferPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate consideration array.
                    tailOffset += offerSize;
                }
                // Write offset to consideration.
                dstHead.offset(ratifyOrder_consideration_head_offset).write(tailOffset);
                // Get pointer to `orderParameters.consideration.length`.
                MemoryPointer srcConsiderationPointer = src
                    .offset(OrderParameters_consideration_head_offset)
                    .readMemoryPointer();
                // Encode the consideration array as a `ReceivedItem[]`.
                uint256 considerationSize = _encodeConsiderationAsReceivedItems(
                    srcConsiderationPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate context array.
                    tailOffset += considerationSize;
                }
                // Write offset to context.
                dstHead.offset(ratifyOrder_context_head_offset).write(tailOffset);
                // Encode context.
                uint256 contextSize = _encodeBytes(
                    toMemoryPointer(context),
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate orderHashes array.
                    tailOffset += contextSize;
                }
                // Write offset to orderHashes.
                dstHead.offset(ratifyOrder_orderHashes_head_offset).write(tailOffset);
                // Encode orderHashes.
                uint256 orderHashesSize = _encodeOrderHashes(
                    toMemoryPointer(orderHashes),
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment the tail offset, now used to determine final size.
                    tailOffset += orderHashesSize;
                    // Derive the final size by including the selector.
                    size = Selector_length + tailOffset;
                }
            }
            /**
             * @dev Takes an order hash, OrderParameters struct, extraData bytes array,
             *      and array of order hashes for each order included as part of the
             *      current fulfillment and encodes it as `authorizeOrder` calldata.
             *      Note that future, new versions of this contract may end up writing
             *      to a memory region that might have been potentially dirtied by the
             *      accumulator. Since the book-keeping for the accumulator does not
             *      update the free memory pointer, it will be necessary to ensure that
             *      all bytes in the memory in the range [dst, dst+size) are fully
             *      updated/written to in this function.
             *
             * @param orderHash       The order hash.
             * @param orderParameters The OrderParameters struct used to construct the
             *                        encoded `authorizeOrder` calldata.
             * @param extraData       The extraData bytes array used to construct the
             *                        encoded `authorizeOrder` calldata.
             * @param orderHashes     An array of bytes32 values representing the order
             *                        hashes of all available orders validated thus far
             *                        as part of current fulfillment.
             *                        Note that this differs from the orderHashes array
             *                        passed to `validateOrder` in that the latter
             *                        includes *all* available and validated orders
             *                        in the final fulfillment, as it is only a subset
             *                        of the final fulfilled orderHashes.
             *
             * @return dst  A memory pointer referencing the encoded `authorizeOrder`
             *              calldata.
             * @return size The size of the bytes array.
             */
            function _encodeAuthorizeOrder(
                bytes32 orderHash,
                OrderParameters memory orderParameters,
                bytes memory extraData,
                bytes32[] memory orderHashes,
                uint256 orderIndex
            ) internal view returns (MemoryPointer dst, uint256 size) {
                // Get free memory pointer to write calldata to.
                MemoryPointer ptr = getFreeMemoryPointer();
                dst = ptr;
                // Write authorizeOrder selector and get pointer to start of calldata.
                dst.write(authorizeOrder_selector);
                dst = dst.offset(authorizeOrder_selector_offset);
                // Get pointer to the beginning of the encoded data.
                MemoryPointer dstHead = dst.offset(authorizeOrder_head_offset);
                // Write offset to zoneParameters to start of calldata.
                dstHead.write(authorizeOrder_zoneParameters_offset);
                // Reuse `dstHead` as pointer to zoneParameters.
                dstHead = dstHead.offset(authorizeOrder_zoneParameters_offset);
                // Write orderHash and fulfiller to zoneParameters.
                dstHead.writeBytes32(orderHash);
                dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender);
                // Get the memory pointer to the order parameters struct.
                MemoryPointer src = orderParameters.toMemoryPointer();
                // Copy offerer, startTime, endTime and zoneHash to zoneParameters.
                dstHead.offset(ZoneParameters_offerer_offset).write(src.readUint256());
                dstHead.offset(ZoneParameters_startTime_offset).write(
                    src.offset(OrderParameters_startTime_offset).readUint256()
                );
                dstHead.offset(ZoneParameters_endTime_offset).write(
                    src.offset(OrderParameters_endTime_offset).readUint256()
                );
                dstHead.offset(ZoneParameters_zoneHash_offset).write(
                    src.offset(OrderParameters_zoneHash_offset).readUint256()
                );
                // Initialize tail offset, used to populate the offer array.
                uint256 tailOffset = ZoneParameters_base_tail_offset;
                // Write offset to `offer`.
                dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset);
                // Get pointer to `orderParameters.offer.length`.
                MemoryPointer srcOfferPointer = src
                    .offset(OrderParameters_offer_head_offset)
                    .readMemoryPointer();
                // Encode the offer array as a `SpentItem[]`.
                uint256 offerSize = _encodeSpentItems(
                    srcOfferPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate consideration array.
                    tailOffset += offerSize;
                }
                // Write offset to consideration.
                dstHead.offset(ZoneParameters_consideration_head_offset).write(
                    tailOffset
                );
                // Get pointer to `orderParameters.consideration.length`.
                MemoryPointer srcConsiderationPointer = src
                    .offset(OrderParameters_consideration_head_offset)
                    .readMemoryPointer();
                // Encode the consideration array as a `ReceivedItem[]`.
                uint256 considerationSize = _encodeConsiderationAsReceivedItems(
                    srcConsiderationPointer,
                    dstHead.offset(tailOffset)
                );
                unchecked {
                    // Increment tail offset, now used to populate extraData array.
                    tailOffset += considerationSize;
                }
                // Write offset to extraData.
                dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset);
                unchecked {
                    // Copy extraData.
                    uint256 extraDataSize = _encodeBytes(
                        toMemoryPointer(extraData),
                        dstHead.offset(tailOffset)
                    );
                    // Increment tail offset, now used to populate orderHashes array.
                    tailOffset += extraDataSize;
                }
                // Write offset to orderHashes.
                dstHead.offset(ZoneParameters_orderHashes_head_offset).write(
                    tailOffset
                );
                // Encode the order hashes array.
                MemoryPointer orderHashesLengthLocation = dstHead.offset(tailOffset);
                unchecked {
                    uint256 orderHashesSize = _encodeOrderHashes(
                        toMemoryPointer(orderHashes),
                        orderHashesLengthLocation
                    );
                    // Increment the tail offset, now used to determine final size.
                    tailOffset += orderHashesSize;
                    // Derive final size including selector and ZoneParameters pointer.
                    size = ZoneParameters_selectorAndPointer_length + tailOffset;
                }
                // Update the free memory pointer.
                setFreeMemoryPointer(dst.offset(size));
                // Track the pointer, size (when performing validateOrder) and pointer
                // to orderHashes length by overriding the salt value on the order.
                orderParameters.salt = ((MemoryPointer.unwrap(ptr) << 128) |
                    (size << 64) |
                    MemoryPointer.unwrap(orderHashesLengthLocation));
                // Write the shortened orderHashes array length.
                orderHashesLengthLocation.write(orderIndex);
                // Modify encoding size to account for the shorter orderHashes array.
                size -= (orderHashes.length - orderIndex) << OneWordShift;
            }
            /**
             * @dev Takes an order hash, OrderParameters struct, extraData bytes array,
             *      and array of order hashes for each order included as part of the
             *      current fulfillment and encodes it as `validateOrder` calldata.
             *      Note that future, new versions of this contract may end up writing
             *      to a memory region that might have been potentially dirtied by the
             *      accumulator. Since the book-keeping for the accumulator does not
             *      update the free memory pointer, it will be necessary to ensure that
             *      all bytes in the memory in the range [dst, dst+size) are fully
             *      updated/written to in this function.
             *
             * @param salt            The salt on the order, which has been repurposed
             *                        to contain relevant pointers and encoding size.
             * @param orderHashes     An array of bytes32 values representing the order
             *                        hashes of all orders included as part of the
             *                        current fulfillment.
             *
             * @return dst  A memory pointer referencing the encoded `validateOrder`
             *              calldata.
             * @return size The size of the bytes array.
             */
            function _encodeValidateOrder(
                uint256 salt,
                bytes32[] memory orderHashes
            ) internal view returns (MemoryPointer dst, uint256 size) {
                dst = MemoryPointer.wrap(salt >> 128);
                size = (salt >> 64) & OffsetOrLengthMask;
                MemoryPointer orderHashesLengthLocation = MemoryPointer.wrap(
                    salt & OffsetOrLengthMask
                );
                // Write validateOrder selector.
                dst.write(validateOrder_selector);
                dst = dst.offset(validateOrder_selector_offset);
                // Encode the order hashes array. Note that this currently modifies
                // order hashes that are known to be properly encoded already and could
                // therefore be skipped.
                _encodeOrderHashes(
                    toMemoryPointer(orderHashes),
                    orderHashesLengthLocation
                );
            }
            /**
             * @dev Takes an order hash and BasicOrderParameters struct (from calldata)
             *      and encodes it as `authorizeOrder` calldata. Note that memory data
             *      is reused from `OrderFulfilled` event data, and the rest of the
             *      calldata is prefixed and postfixed to this memory region. Note that
             *      the memory region before the spent and received items on the
             *      `OrderFulfilled` event are overwritten, which implies that this
             *      function will need to be modified should the layout of that event
             *      data change in the future.
             *
             * @param orderHash  The order hash.
             *
             * @return ptr  A memory pointer referencing the encoded `authorizeOrder`
             *              calldata with extra padding at the start to word align.
             * @return size The size of the bytes array.
             */
            function _encodeAuthorizeBasicOrder(
                bytes32 orderHash
            )
                internal
                view
                returns (
                    MemoryPointer ptr,
                    uint256 size,
                    uint256 memoryLocationForOrderHashes
                )
            {
                unchecked {
                    // Derive offset to pre `OrderFulfilled`'s spent item event data
                    // using base offset & total original recipients.
                    ptr = MemoryPointer.wrap(
                        authorizeOrder_calldata_baseOffset +
                            (CalldataPointer
                                .wrap(
                                    BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                                )
                                .readUint256() << OneWordShift)
                    );
                }
                MemoryPointer dst = ptr;
                // Write authorizeOrder selector and get pointer to start of calldata.
                dst.write(authorizeOrder_selector);
                dst = dst.offset(authorizeOrder_selector_offset);
                // Get pointer to the beginning of the encoded data.
                MemoryPointer dstHead = dst.offset(authorizeOrder_head_offset);
                // Write offset to zoneParameters to start of calldata.
                dstHead.write(authorizeOrder_zoneParameters_offset);
                // Reuse `dstHead` as pointer to zoneParameters.
                dstHead = dstHead.offset(authorizeOrder_zoneParameters_offset);
                // Write offerer, orderHash and fulfiller to zoneParameters.
                dstHead.writeBytes32(orderHash);
                dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender);
                dstHead.offset(ZoneParameters_offerer_offset).write(
                    CalldataPointer.wrap(BasicOrder_offerer_cdPtr).readAddress()
                );
                // Copy startTime, endTime and zoneHash to zoneParameters.
                CalldataPointer.wrap(BasicOrder_startTime_cdPtr).copy(
                    dstHead.offset(ZoneParameters_startTime_offset),
                    BasicOrder_startTimeThroughZoneHash_size
                );
                // Initialize tail offset, used for the offer + consideration arrays.
                uint256 tailOffset = ZoneParameters_base_tail_offset;
                // Write offset to offer from event data into target calldata.
                dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset);
                unchecked {
                    // Write consideration offset next (located 5 words after offer).
                    dstHead.offset(ZoneParameters_consideration_head_offset).write(
                        tailOffset + BasicOrder_consideration_offset_from_offer
                    );
                    // Retrieve the length of additional recipients.
                    uint256 additionalRecipientsLength = CalldataPointer
                        .wrap(BasicOrder_addlRecipients_length_cdPtr)
                        .readUint256();
                    // Derive size of offer and consideration data.
                    // 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar
                    uint256 offerAndConsiderationSize = OrderFulfilled_baseDataSize +
                        (additionalRecipientsLength * ReceivedItem_size);
                    // Increment tail offset, now used to populate extraData array.
                    tailOffset += offerAndConsiderationSize;
                }
                // Write empty bytes for extraData.
                dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset);
                dstHead.offset(tailOffset).write(0);
                unchecked {
                    // Increment tail offset, now used to populate orderHashes array.
                    tailOffset += OneWord;
                }
                // Write offset to orderHashes.
                dstHead.offset(ZoneParameters_orderHashes_head_offset).write(
                    tailOffset
                );
                memoryLocationForOrderHashes = MemoryPointer.unwrap(
                    dstHead.offset(tailOffset)
                );
                // Write length = 0 to the orderHashes array.
                dstHead.offset(tailOffset).write(0);
                unchecked {
                    // Write the single order hash to the orderHashes array.
                    dstHead.offset(tailOffset + OneWord).writeBytes32(orderHash);
                    // Final size: selector, ZoneParameters pointer, orderHashes & tail.
                    size = ZoneParameters_basicOrderFixedElements_length + tailOffset;
                }
            }
            /**
             * @dev Takes pointers to already-encoded data and modifies it so that
             *      it is properly formatted for a `validateOrder` call.
             *
             * @param dst                          A memory pointer referencing the
             *                                     encoded `validateOrder` calldata.
             * @param memoryLocationForOrderHashes A memory pointer referencing where
             *                                     to encode orderHashes length of 1.
             */
            function _encodeValidateBasicOrder(
                MemoryPointer dst,
                uint256 memoryLocationForOrderHashes
            ) internal pure {
                // Write validateOrder selector and get pointer to start of calldata.
                dst.write(validateOrder_selector);
                // Write length = 1 to the orderHashes array. Note that size should now
                // be one word larger than the provided size.
                MemoryPointer.wrap(memoryLocationForOrderHashes).write(1);
            }
            /**
             * @dev Takes a memory pointer to an array of bytes32 values representing
             *      the order hashes included as part of the fulfillment and a memory
             *      pointer to a location to copy it to, and copies the source data to
             *      the destination in memory.
             *
             * @param srcLength A memory pointer referencing the order hashes array to
             *                  be copied (and pointing to the length of the array).
             * @param dstLength A memory pointer referencing the location in memory to
             *                  copy the orderHashes array to (and pointing to the
             *                  length of the copied array).
             *
             * @return size The size of the order hashes array (including the length).
             */
            function _encodeOrderHashes(
                MemoryPointer srcLength,
                MemoryPointer dstLength
            ) internal view returns (uint256 size) {
                // Read length of the array from source and write to destination.
                uint256 length = srcLength.readUint256();
                dstLength.write(length);
                unchecked {
                    // Determine head & tail size as one word per element in the array.
                    uint256 headAndTailSize = length << OneWordShift;
                    // Copy the tail starting from the next element of the source to the
                    // next element of the destination.
                    srcLength.next().copy(dstLength.next(), headAndTailSize);
                    // Set size to the length of the tail plus one word for length.
                    size = headAndTailSize + OneWord;
                }
            }
            /**
             * @dev Takes a memory pointer to an offer or consideration array and a
             *      memory pointer to a location to copy it to, and copies the source
             *      data to the destination in memory as a SpentItem array.
             *
             * @param srcLength A memory pointer referencing the offer or consideration
             *                  array to be copied as a SpentItem array (and pointing to
             *                  the length of the original array).
             * @param dstLength A memory pointer referencing the location in memory to
             *                  copy the offer array to (and pointing to the length of
             *                  the copied array).
             *
             * @return size The size of the SpentItem array (including the length).
             */
            function _encodeSpentItems(
                MemoryPointer srcLength,
                MemoryPointer dstLength
            ) internal pure returns (uint256 size) {
                assembly {
                    // Read length of the array from source and write to destination.
                    let length := mload(srcLength)
                    mstore(dstLength, length)
                    // Get pointer to first item's head position in the array,
                    // containing the item's pointer in memory. The head pointer will be
                    // incremented until it reaches the tail position (start of the
                    // array data).
                    let mPtrHead := add(srcLength, OneWord)
                    // Position in memory to write next item for calldata. Since
                    // SpentItem has a fixed length, the array elements do not contain
                    // head elements in calldata, they are concatenated together after
                    // the array length.
                    let cdPtrData := add(dstLength, OneWord)
                    // Pointer to end of array head in memory.
                    let mPtrHeadEnd := add(mPtrHead, shl(OneWordShift, length))
                    for {
                    } lt(mPtrHead, mPtrHeadEnd) {
                    } {
                        // Read pointer to data for array element from head position.
                        let mPtrTail := mload(mPtrHead)
                        // Copy itemType, token, identifier, amount to calldata.
                        mstore(cdPtrData, mload(mPtrTail))
                        mstore(
                            add(cdPtrData, Common_token_offset),
                            mload(add(mPtrTail, Common_token_offset))
                        )
                        mstore(
                            add(cdPtrData, Common_identifier_offset),
                            mload(add(mPtrTail, Common_identifier_offset))
                        )
                        mstore(
                            add(cdPtrData, Common_amount_offset),
                            mload(add(mPtrTail, Common_amount_offset))
                        )
                        mPtrHead := add(mPtrHead, OneWord)
                        cdPtrData := add(cdPtrData, SpentItem_size)
                    }
                    size := add(OneWord, shl(SpentItem_size_shift, length))
                }
            }
            /**
             * @dev Takes a memory pointer to an consideration array and a memory
             *      pointer to a location to copy it to, and copies the source data to
             *      the destination in memory as a ReceivedItem array.
             *
             * @param srcLength A memory pointer referencing the consideration array to
             *                  be copied as a ReceivedItem array (and pointing to the
             *                  length of the original array).
             * @param dstLength A memory pointer referencing the location in memory to
             *                  copy the consideration array to as a ReceivedItem array
             *                  (and pointing to the length of the new array).
             *
             * @return size The size of the ReceivedItem array (including the length).
             */
            function _encodeConsiderationAsReceivedItems(
                MemoryPointer srcLength,
                MemoryPointer dstLength
            ) internal view returns (uint256 size) {
                unchecked {
                    // Read length of the array from source and write to destination.
                    uint256 length = srcLength.readUint256();
                    dstLength.write(length);
                    // Get pointer to first item's head position in the array,
                    // containing the item's pointer in memory. The head pointer will be
                    // incremented until it reaches the tail position (start of the
                    // array data).
                    MemoryPointer srcHead = srcLength.next();
                    MemoryPointer srcHeadEnd = srcHead.offset(length << OneWordShift);
                    // Position in memory to write next item for calldata. Since
                    // ReceivedItem has a fixed length, the array elements do not
                    // contain offsets in calldata, they are concatenated together after
                    // the array length.
                    MemoryPointer dstHead = dstLength.next();
                    while (srcHead.lt(srcHeadEnd)) {
                        MemoryPointer srcTail = srcHead.pptr();
                        srcTail.copy(dstHead, ReceivedItem_size);
                        srcHead = srcHead.next();
                        dstHead = dstHead.offset(ReceivedItem_size);
                    }
                    size = OneWord + (length * ReceivedItem_size);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import { ConduitItemType } from "./ConduitEnums.sol";
        /**
         * @dev A ConduitTransfer is a struct that contains the information needed for a
         *      conduit to transfer an item from one address to another.
         */
        struct ConduitTransfer {
            ConduitItemType itemType;
            address token;
            address from;
            address to;
            uint256 identifier;
            uint256 amount;
        }
        /**
         * @dev A ConduitBatch1155Transfer is a struct that contains the information
         *      needed for a conduit to transfer a batch of ERC-1155 tokens from one
         *      address to another.
         */
        struct ConduitBatch1155Transfer {
            address token;
            address from;
            address to;
            uint256[] ids;
            uint256[] amounts;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            OrderParameters
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { GettersAndDerivers } from "./GettersAndDerivers.sol";
        import {
            TokenTransferrerErrors
        } from "seaport-types/src/interfaces/TokenTransferrerErrors.sol";
        import { CounterManager } from "./CounterManager.sol";
        import {
            AdditionalRecipient_size_shift,
            AddressDirtyUpperBitThreshold,
            BasicOrder_additionalRecipients_head_cdPtr,
            BasicOrder_additionalRecipients_head_ptr,
            BasicOrder_addlRecipients_length_cdPtr,
            BasicOrder_basicOrderType_cdPtr,
            BasicOrder_basicOrderType_range,
            BasicOrder_considerationToken_cdPtr,
            BasicOrder_offerer_cdPtr,
            BasicOrder_offerToken_cdPtr,
            BasicOrder_parameters_cdPtr,
            BasicOrder_parameters_ptr,
            BasicOrder_signature_cdPtr,
            BasicOrder_signature_ptr,
            BasicOrder_zone_cdPtr
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            Error_selector_offset,
            MissingItemAmount_error_length,
            MissingItemAmount_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        import {
            _revertInvalidBasicOrderParameterEncoding,
            _revertMissingOriginalConsiderationItems
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        /**
         * @title Assertions
         * @author 0age
         * @notice Assertions contains logic for making various assertions that do not
         *         fit neatly within a dedicated semantic scope.
         */
        contract Assertions is
            GettersAndDerivers,
            CounterManager,
            TokenTransferrerErrors
        {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(
                address conduitController
            ) GettersAndDerivers(conduitController) {}
            /**
             * @dev Internal view function to ensure that the supplied consideration
             *      array length on a given set of order parameters is not less than the
             *      original consideration array length for that order and to retrieve
             *      the current counter for a given order's offerer and zone and use it
             *      to derive the order hash.
             *
             * @param orderParameters The parameters of the order to hash.
             *
             * @return The hash.
             */
            function _assertConsiderationLengthAndGetOrderHash(
                OrderParameters memory orderParameters
            ) internal view returns (bytes32) {
                // Ensure supplied consideration array length is not less than original.
                _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
                    orderParameters.consideration.length,
                    orderParameters.totalOriginalConsiderationItems
                );
                // Derive and return order hash using current counter for the offerer.
                return
                    _deriveOrderHash(
                        orderParameters,
                        _getCounter(orderParameters.offerer)
                    );
            }
            /**
             * @dev Internal pure function to ensure that the supplied consideration
             *      array length for an order to be fulfilled is not less than the
             *      original consideration array length for that order.
             *
             * @param suppliedConsiderationItemTotal The number of consideration items
             *                                       supplied when fulfilling the order.
             * @param originalConsiderationItemTotal The number of consideration items
             *                                       supplied on initial order creation.
             */
            function _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
                uint256 suppliedConsiderationItemTotal,
                uint256 originalConsiderationItemTotal
            ) internal pure {
                // Ensure supplied consideration array length is not less than original.
                if (suppliedConsiderationItemTotal < originalConsiderationItemTotal) {
                    _revertMissingOriginalConsiderationItems();
                }
            }
            /**
             * @dev Internal pure function to ensure that a given item amount is not
             *      zero.
             *
             * @param amount The amount to check.
             */
            function _assertNonZeroAmount(uint256 amount) internal pure {
                assembly {
                    if iszero(amount) {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, MissingItemAmount_error_selector)
                        // revert(abi.encodeWithSignature("MissingItemAmount()"))
                        revert(Error_selector_offset, MissingItemAmount_error_length)
                    }
                }
            }
            /**
             * @dev Internal pure function to validate calldata offsets for dynamic
             *      types in BasicOrderParameters and other parameters. This ensures
             *      that functions using the calldata object normally will be using the
             *      same data as the assembly functions and that values that are bound
             *      to a given range are within that range. Note that no parameters are
             *      supplied as all basic order functions use the same calldata
             *      encoding.
             */
            function _assertValidBasicOrderParameters() internal pure {
                // Declare a boolean designating basic order parameter offset validity.
                bool validOffsets;
                // Utilize assembly in order to read offset data directly from calldata.
                assembly {
                    /*
                     * Checks:
                     * 1. Order parameters struct offset == 0x20
                     * 2. Additional recipients arr offset == 0x240
                     * 3. Signature offset == 0x260 + (recipients.length * 0x40)
                     * 4. BasicOrderType between 0 and 23 (i.e. < 24)
                     * 5. Offerer, zone, offer token, and consideration token have no
                     *    upper dirty bits — each argument is type(uint160).max or less
                     */
                    validOffsets := and(
                        and(
                            and(
                                // Order parameters at cd 0x04 offset = 0x20.
                                eq(
                                    calldataload(BasicOrder_parameters_cdPtr),
                                    BasicOrder_parameters_ptr
                                ),
                                // Additional recipients at cd 0x224 offset = 0x240.
                                eq(
                                    calldataload(
                                        BasicOrder_additionalRecipients_head_cdPtr
                                    ),
                                    BasicOrder_additionalRecipients_head_ptr
                                )
                            ),
                            // Signature offset = 0x260 + recipients.length * 0x40.
                            eq(
                                // Load signature offset from calldata 0x244.
                                calldataload(BasicOrder_signature_cdPtr),
                                // Expected offset = start of recipients + len * 64.
                                add(
                                    BasicOrder_signature_ptr,
                                    shl(
                                        // Each additional recipient length = 0x40.
                                        AdditionalRecipient_size_shift,
                                        // Additional recipients length at cd 0x264.
                                        calldataload(
                                            BasicOrder_addlRecipients_length_cdPtr
                                        )
                                    )
                                )
                            )
                        ),
                        and(
                            // Ensure BasicOrderType parameter is less than 0x18.
                            lt(
                                // BasicOrderType parameter = calldata offset 0x124.
                                calldataload(BasicOrder_basicOrderType_cdPtr),
                                // Value should be less than 24.
                                BasicOrder_basicOrderType_range
                            ),
                            // Ensure no dirty upper bits are present on offerer,
                            // zone, offer token, or consideration token.
                            lt(
                                or(
                                    or(
                                        // Offerer parameter = calldata offset 0x84.
                                        calldataload(BasicOrder_offerer_cdPtr),
                                        // Zone parameter = calldata offset 0xa4.
                                        calldataload(BasicOrder_zone_cdPtr)
                                    ),
                                    or(
                                        // Offer token parameter = cd offset 0xc4.
                                        calldataload(BasicOrder_offerToken_cdPtr),
                                        // Consideration parameter = offset 0x24.
                                        calldataload(
                                            BasicOrder_considerationToken_cdPtr
                                        )
                                    )
                                ),
                                AddressDirtyUpperBitThreshold
                            )
                        )
                    )
                }
                // Revert with an error if basic order parameter offsets are invalid.
                if (!validOffsets) {
                    _revertInvalidBasicOrderParameterEncoding();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            SignatureVerificationErrors
        } from "seaport-types/src/interfaces/SignatureVerificationErrors.sol";
        import { LowLevelHelpers } from "./LowLevelHelpers.sol";
        import {
            ECDSA_MaxLength,
            ECDSA_signature_s_offset,
            ECDSA_signature_v_offset,
            ECDSA_twentySeventhAndTwentyEighthBytesSet,
            Ecrecover_args_size,
            Ecrecover_precompile,
            EIP1271_isValidSignature_calldata_baseLength,
            EIP1271_isValidSignature_digest_negativeOffset,
            EIP1271_isValidSignature_selector_negativeOffset,
            EIP1271_isValidSignature_selector,
            EIP1271_isValidSignature_signature_head_offset,
            EIP2098_allButHighestBitMask,
            MaxUint8,
            OneWord,
            Signature_lower_v
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            BadContractSignature_error_length,
            BadContractSignature_error_selector,
            BadSignatureV_error_length,
            BadSignatureV_error_selector,
            BadSignatureV_error_v_ptr,
            Error_selector_offset,
            InvalidSignature_error_length,
            InvalidSignature_error_selector,
            InvalidSigner_error_length,
            InvalidSigner_error_selector
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title SignatureVerification
         * @author 0age
         * @notice SignatureVerification contains logic for verifying signatures.
         */
        contract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers {
            /**
             * @dev Internal view function to verify the signature of an order. An
             *      ERC-1271 fallback will be attempted if either the signature length
             *      is not 64 or 65 bytes or if the recovered signer does not match the
             *      supplied signer.
             *
             * @param signer                  The signer for the order.
             * @param digest                  The digest to verify signature against.
             * @param originalDigest          The original digest to verify signature
             *                                against.
             * @param originalSignatureLength The original signature length.
             * @param signature               A signature from the signer indicating
             *                                that the order has been approved.
             */
            function _assertValidSignature(
                address signer,
                bytes32 digest,
                bytes32 originalDigest,
                uint256 originalSignatureLength,
                bytes memory signature
            ) internal view {
                // Declare value for ecrecover equality or 1271 call success status.
                bool success;
                // Utilize assembly to perform optimized signature verification check.
                assembly {
                    // Ensure that first word of scratch space is empty.
                    mstore(0, 0)
                    // Get the length of the signature.
                    let signatureLength := mload(signature)
                    // Get the pointer to the value preceding the signature length.
                    // This will be used for temporary memory overrides - either the
                    // signature head for isValidSignature or the digest for ecrecover.
                    let wordBeforeSignaturePtr := sub(signature, OneWord)
                    // Cache the current value behind the signature to restore it later.
                    let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)
                    // Declare lenDiff + recoveredSigner scope to manage stack pressure.
                    {
                        // Take the difference between the max ECDSA signature length
                        // and the actual signature length. Overflow desired for any
                        // values > 65. If the diff is not 0 or 1, it is not a valid
                        // ECDSA signature - move on to EIP1271 check.
                        let lenDiff := sub(ECDSA_MaxLength, signatureLength)
                        // Declare variable for recovered signer.
                        let recoveredSigner
                        // If diff is 0 or 1, it may be an ECDSA signature.
                        // Try to recover signer.
                        if iszero(gt(lenDiff, 1)) {
                            // Read the signature `s` value.
                            let originalSignatureS := mload(
                                add(signature, ECDSA_signature_s_offset)
                            )
                            // Read the first byte of the word after `s`. If the
                            // signature is 65 bytes, this will be the real `v` value.
                            // If not, it will need to be modified - doing it this way
                            // saves an extra condition.
                            let v := byte(
                                0,
                                mload(add(signature, ECDSA_signature_v_offset))
                            )
                            // If lenDiff is 1, parse 64-byte signature as ECDSA.
                            if lenDiff {
                                // Extract yParity from highest bit of vs and add 27 to
                                // get v.
                                v := add(
                                    shr(MaxUint8, originalSignatureS),
                                    Signature_lower_v
                                )
                                // Extract canonical s from vs, all but the highest bit.
                                // Temporarily overwrite the original `s` value in the
                                // signature.
                                mstore(
                                    add(signature, ECDSA_signature_s_offset),
                                    and(
                                        originalSignatureS,
                                        EIP2098_allButHighestBitMask
                                    )
                                )
                            }
                            // Temporarily overwrite the signature length with `v` to
                            // conform to the expected input for ecrecover.
                            mstore(signature, v)
                            // Temporarily overwrite the word before the length with
                            // `digest` to conform to the expected input for ecrecover.
                            mstore(wordBeforeSignaturePtr, digest)
                            // Attempt to recover the signer for the given signature. Do
                            // not check the call status as ecrecover will return a null
                            // address if the signature is invalid.
                            pop(
                                staticcall(
                                    gas(),
                                    Ecrecover_precompile, // Call ecrecover precompile.
                                    wordBeforeSignaturePtr, // Use data memory location.
                                    Ecrecover_args_size, // Size of digest, v, r, and s.
                                    0, // Write result to scratch space.
                                    OneWord // Provide size of returned result.
                                )
                            )
                            // Restore cached word before signature.
                            mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                            // Restore cached signature length.
                            mstore(signature, signatureLength)
                            // Restore cached signature `s` value.
                            mstore(
                                add(signature, ECDSA_signature_s_offset),
                                originalSignatureS
                            )
                            // Read the recovered signer from the buffer given as return
                            // space for ecrecover.
                            recoveredSigner := mload(0)
                        }
                        // Set success to true if the signature provided was a valid
                        // ECDSA signature and the signer is not the null address. Use
                        // gt instead of direct as success is used outside of assembly.
                        success := and(eq(signer, recoveredSigner), gt(signer, 0))
                    }
                    // If the signature was not verified with ecrecover, try EIP1271.
                    if iszero(success) {
                        // Reset the original signature length.
                        mstore(signature, originalSignatureLength)
                        // Temporarily overwrite the word before the signature length
                        // and use it as the head of the signature input to
                        // `isValidSignature`, which has a value of 64.
                        mstore(
                            wordBeforeSignaturePtr,
                            EIP1271_isValidSignature_signature_head_offset
                        )
                        // Get pointer to use for the selector of `isValidSignature`.
                        let selectorPtr := sub(
                            signature,
                            EIP1271_isValidSignature_selector_negativeOffset
                        )
                        // Cache the value currently stored at the selector pointer.
                        let cachedWordOverwrittenBySelector := mload(selectorPtr)
                        // Cache the value currently stored at the digest pointer.
                        let cachedWordOverwrittenByDigest := mload(
                            sub(
                                signature,
                                EIP1271_isValidSignature_digest_negativeOffset
                            )
                        )
                        // Write the selector first, since it overlaps the digest.
                        mstore(selectorPtr, EIP1271_isValidSignature_selector)
                        // Next, write the original digest.
                        mstore(
                            sub(
                                signature,
                                EIP1271_isValidSignature_digest_negativeOffset
                            ),
                            originalDigest
                        )
                        // Call signer with `isValidSignature` to validate signature.
                        success := staticcall(
                            gas(),
                            signer,
                            selectorPtr,
                            add(
                                originalSignatureLength,
                                EIP1271_isValidSignature_calldata_baseLength
                            ),
                            0,
                            OneWord
                        )
                        // Determine if the signature is valid on successful calls.
                        if success {
                            // If first word of scratch space does not contain EIP-1271
                            // signature selector, revert.
                            if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) {
                                // Revert with bad 1271 signature if signer has code.
                                if extcodesize(signer) {
                                    // Bad contract signature.
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(0, BadContractSignature_error_selector)
                                    // revert(abi.encodeWithSignature(
                                    //     "BadContractSignature()"
                                    // ))
                                    revert(
                                        Error_selector_offset,
                                        BadContractSignature_error_length
                                    )
                                }
                                // Check if signature length was invalid.
                                if gt(sub(ECDSA_MaxLength, signatureLength), 1) {
                                    // Revert with generic invalid signature error.
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(0, InvalidSignature_error_selector)
                                    // revert(abi.encodeWithSignature(
                                    //     "InvalidSignature()"
                                    // ))
                                    revert(
                                        Error_selector_offset,
                                        InvalidSignature_error_length
                                    )
                                }
                                // Check if v was invalid.
                                if and(
                                    eq(signatureLength, ECDSA_MaxLength),
                                    iszero(
                                        byte(
                                            byte(
                                                0,
                                                mload(
                                                    add(
                                                        signature,
                                                        ECDSA_signature_v_offset
                                                    )
                                                )
                                            ),
                                            ECDSA_twentySeventhAndTwentyEighthBytesSet
                                        )
                                    )
                                ) {
                                    // Revert with invalid v value.
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(0, BadSignatureV_error_selector)
                                    mstore(
                                        BadSignatureV_error_v_ptr,
                                        byte(
                                            0,
                                            mload(
                                                add(signature, ECDSA_signature_v_offset)
                                            )
                                        )
                                    )
                                    // revert(abi.encodeWithSignature(
                                    //     "BadSignatureV(uint8)", v
                                    // ))
                                    revert(
                                        Error_selector_offset,
                                        BadSignatureV_error_length
                                    )
                                }
                                // Revert with generic invalid signer error message.
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(0, InvalidSigner_error_selector)
                                // revert(abi.encodeWithSignature("InvalidSigner()"))
                                revert(
                                    Error_selector_offset,
                                    InvalidSigner_error_length
                                )
                            }
                        }
                        // Restore the cached values overwritten by selector, digest and
                        // signature head.
                        mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                        mstore(selectorPtr, cachedWordOverwrittenBySelector)
                        mstore(
                            sub(
                                signature,
                                EIP1271_isValidSignature_digest_negativeOffset
                            ),
                            cachedWordOverwrittenByDigest
                        )
                    }
                }
                // If the call failed...
                if (!success) {
                    // Revert and pass reason along if one was returned.
                    _revertWithReasonIfOneIsReturned();
                    // Otherwise, revert with error indicating bad contract signature.
                    assembly {
                        // Store left-padded selector with push4, mem[28:32] = selector
                        mstore(0, BadContractSignature_error_selector)
                        // revert(abi.encodeWithSignature("BadContractSignature()"))
                        revert(Error_selector_offset, BadContractSignature_error_length)
                    }
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /*
         * -------------------------- Disambiguation & Other Notes ---------------------
         *    - The term "head" is used as it is in the documentation for ABI encoding,
         *      but only in reference to dynamic types, i.e. it always refers to the
         *      offset or pointer to the body of a dynamic type. In calldata, the head
         *      is always an offset (relative to the parent object), while in memory,
         *      the head is always the pointer to the body. More information found here:
         *      https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding
         *        - Note that the length of an array is separate from and precedes the
         *          head of the array.
         *
         *    - The term "body" is used in place of the term "head" used in the ABI
         *      documentation. It refers to the start of the data for a dynamic type,
         *      e.g. the first word of a struct or the first word of the first element
         *      in an array.
         *
         *    - The term "pointer" is used to describe the absolute position of a value
         *      and never an offset relative to another value.
         *        - The suffix "_ptr" refers to a memory pointer.
         *        - The suffix "_cdPtr" refers to a calldata pointer.
         *
         *    - The term "offset" is used to describe the position of a value relative
         *      to some parent value. For example, OrderParameters_conduit_offset is the
         *      offset to the "conduit" value in the OrderParameters struct relative to
         *      the start of the body.
         *        - Note: Offsets are used to derive pointers.
         *
         *    - Some structs have pointers defined for all of their fields in this file.
         *      Lines which are commented out are fields that are not used in the
         *      codebase but have been left in for readability.
         */
        uint256 constant ThirtyOneBytes = 0x1f;
        uint256 constant OneWord = 0x20;
        uint256 constant TwoWords = 0x40;
        uint256 constant ThreeWords = 0x60;
        uint256 constant OneWordShift = 0x5;
        uint256 constant TwoWordsShift = 0x6;
        uint256 constant FreeMemoryPointerSlot = 0x40;
        uint256 constant ZeroSlot = 0x60;
        uint256 constant DefaultFreeMemoryPointer = 0x80;
        uint256 constant Slot0x80 = 0x80;
        uint256 constant Slot0xA0 = 0xa0;
        uint256 constant Slot0xC0 = 0xc0;
        uint256 constant Generic_error_selector_offset = 0x1c;
        // abi.encodeWithSignature("transferFrom(address,address,uint256)")
        uint256 constant ERC20_transferFrom_signature = (
            0x23b872dd00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC20_transferFrom_sig_ptr = 0x0;
        uint256 constant ERC20_transferFrom_from_ptr = 0x04;
        uint256 constant ERC20_transferFrom_to_ptr = 0x24;
        uint256 constant ERC20_transferFrom_amount_ptr = 0x44;
        uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
        // abi.encodeWithSignature(
        //     "safeTransferFrom(address,address,uint256,uint256,bytes)"
        // )
        uint256 constant ERC1155_safeTransferFrom_signature = (
            0xf242432a00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;
        uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;
        uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;
        uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;
        uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;
        uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;
        uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;
        uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196
        uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;
        // abi.encodeWithSignature(
        //     "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
        // )
        uint256 constant ERC1155_safeBatchTransferFrom_signature = (
            0x2eb2c2d600000000000000000000000000000000000000000000000000000000
        );
        // bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(
        //     bytes32(ERC1155_safeBatchTransferFrom_signature)
        // );
        uint256 constant ERC721_transferFrom_signature = (
            0x23b872dd00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC721_transferFrom_sig_ptr = 0x0;
        uint256 constant ERC721_transferFrom_from_ptr = 0x04;
        uint256 constant ERC721_transferFrom_to_ptr = 0x24;
        uint256 constant ERC721_transferFrom_id_ptr = 0x44;
        uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
        /*
         *  error NoContract(address account)
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x00: account
         * Revert buffer is memory[0x1c:0x40]
         */
        uint256 constant NoContract_error_selector = 0x5f15d672;
        uint256 constant NoContract_error_account_ptr = 0x20;
        uint256 constant NoContract_error_length = 0x24;
        /*
         *  error TokenTransferGenericFailure(
         *      address token,
         *      address from,
         *      address to,
         *      uint256 identifier,
         *      uint256 amount
         *  )
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x20: token
         *    - 0x40: from
         *    - 0x60: to
         *    - 0x80: identifier
         *    - 0xa0: amount
         * Revert buffer is memory[0x1c:0xc0]
         */
        uint256 constant TokenTransferGenericFailure_error_selector = 0xf486bc87;
        uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x20;
        uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x40;
        uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x60;
        uint256 constant TokenTransferGenericFailure_error_identifier_ptr = 0x80;
        uint256 constant TokenTransferGenericFailure_err_identifier_ptr = 0x80;
        uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0xa0;
        uint256 constant TokenTransferGenericFailure_error_length = 0xa4;
        uint256 constant ExtraGasBuffer = 0x20;
        uint256 constant CostPerWord = 0x3;
        uint256 constant MemoryExpansionCoefficientShift = 0x9;
        // Values are offset by 32 bytes in order to write the token to the beginning
        // in the event of a revert
        uint256 constant BatchTransfer1155Params_ptr = 0x24;
        uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;
        uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;
        uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;
        uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;
        uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;
        uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;
        uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;
        // uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;
        // uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;
        uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;
        uint256 constant ConduitBatch1155Transfer_from_offset = 0x20;
        uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;
        // uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;
        uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;
        uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;
        // uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;
        // Note: abbreviated version of above constant to adhere to line length limit.
        uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;
        uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;
        uint256 constant Invalid1155BatchTransferEncoding_length = 0x04;
        uint256 constant Invalid1155BatchTransferEncoding_selector = (
            0xeba2084c00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155BatchTransferGenericFailure_error_signature = (
            0xafc445e200000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;
        uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;
        /*
         *  error BadReturnValueFromERC20OnTransfer(
         *      address token, address from, address to, uint256 amount
         *  )
         *    - Defined in TokenTransferrerErrors.sol
         *  Memory layout:
         *    - 0x00: Left-padded selector (data begins at 0x1c)
         *    - 0x00: token
         *    - 0x20: from
         *    - 0x40: to
         *    - 0x60: amount
         * Revert buffer is memory[0x1c:0xa0]
         */
        uint256 constant BadReturnValueFromERC20OnTransfer_error_selector = 0x98891923;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x20;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x40;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x60;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x80;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title TokenTransferrerErrors
         */
        interface TokenTransferrerErrors {
            /**
             * @dev Revert with an error when an ERC721 transfer with amount other than
             *      one is attempted.
             *
             * @param amount The amount of the ERC721 tokens to transfer.
             */
            error InvalidERC721TransferAmount(uint256 amount);
            /**
             * @dev Revert with an error when attempting to fulfill an order where an
             *      item has an amount of zero.
             */
            error MissingItemAmount();
            /**
             * @dev Revert with an error when attempting to fulfill an order where an
             *      item has unused parameters. This includes both the token and the
             *      identifier parameters for native transfers as well as the identifier
             *      parameter for ERC20 transfers. Note that the conduit does not
             *      perform this check, leaving it up to the calling channel to enforce
             *      when desired.
             */
            error UnusedItemParameters();
            /**
             * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token
             *      transfer reverts.
             *
             * @param token      The token for which the transfer was attempted.
             * @param from       The source of the attempted transfer.
             * @param to         The recipient of the attempted transfer.
             * @param identifier The identifier for the attempted transfer.
             * @param amount     The amount for the attempted transfer.
             */
            error TokenTransferGenericFailure(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount
            );
            /**
             * @dev Revert with an error when a batch ERC1155 token transfer reverts.
             *
             * @param token       The token for which the transfer was attempted.
             * @param from        The source of the attempted transfer.
             * @param to          The recipient of the attempted transfer.
             * @param identifiers The identifiers for the attempted transfer.
             * @param amounts     The amounts for the attempted transfer.
             */
            error ERC1155BatchTransferGenericFailure(
                address token,
                address from,
                address to,
                uint256[] identifiers,
                uint256[] amounts
            );
            /**
             * @dev Revert with an error when an ERC20 token transfer returns a falsey
             *      value.
             *
             * @param token      The token for which the ERC20 transfer was attempted.
             * @param from       The source of the attempted ERC20 transfer.
             * @param to         The recipient of the attempted ERC20 transfer.
             * @param amount     The amount for the attempted ERC20 transfer.
             */
            error BadReturnValueFromERC20OnTransfer(
                address token,
                address from,
                address to,
                uint256 amount
            );
            /**
             * @dev Revert with an error when an account being called as an assumed
             *      contract does not have code and returns no data.
             *
             * @param account The account that should contain code.
             */
            error NoContract(address account);
            /**
             * @dev Revert with an error when attempting to execute an 1155 batch
             *      transfer using calldata not produced by default ABI encoding or with
             *      different lengths for ids and amounts arrays.
             */
            error Invalid1155BatchTransferEncoding();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            OrderParameters
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import { ConsiderationBase } from "./ConsiderationBase.sol";
        import {
            Create2AddressDerivation_length,
            Create2AddressDerivation_ptr,
            EIP_712_PREFIX,
            EIP712_ConsiderationItem_size,
            EIP712_DigestPayload_size,
            EIP712_DomainSeparator_offset,
            EIP712_OfferItem_size,
            EIP712_Order_size,
            EIP712_OrderHash_offset,
            FreeMemoryPointerSlot,
            information_conduitController_offset,
            information_domainSeparator_offset,
            information_length,
            information_version_cd_offset,
            information_version_offset,
            information_versionLengthPtr,
            information_versionWithLength,
            MaskOverByteTwelve,
            MaskOverLastTwentyBytes,
            OneWord,
            OneWordShift,
            OrderParameters_consideration_head_offset,
            OrderParameters_counter_offset,
            OrderParameters_offer_head_offset,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        /**
         * @title GettersAndDerivers
         * @author 0age
         * @notice ConsiderationInternal contains pure and internal view functions
         *         related to getting or deriving various values.
         */
        contract GettersAndDerivers is ConsiderationBase {
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(
                address conduitController
            ) ConsiderationBase(conduitController) {}
            /**
             * @dev Internal view function to derive the order hash for a given order.
             *      Note that only the original consideration items are included in the
             *      order hash, as additional consideration items may be supplied by the
             *      caller.
             *
             * @param orderParameters The parameters of the order to hash.
             * @param counter         The counter of the order to hash.
             *
             * @return orderHash The hash.
             */
            function _deriveOrderHash(
                OrderParameters memory orderParameters,
                uint256 counter
            ) internal view returns (bytes32 orderHash) {
                // Get length of original consideration array and place it on the stack.
                uint256 originalConsiderationLength = (
                    orderParameters.totalOriginalConsiderationItems
                );
                /*
                 * Memory layout for an array of structs (dynamic or not) is similar
                 * to ABI encoding of dynamic types, with a head segment followed by
                 * a data segment. The main difference is that the head of an element
                 * is a memory pointer rather than an offset.
                 */
                // Declare a variable for the derived hash of the offer array.
                bytes32 offerHash;
                // Read offer item EIP-712 typehash from runtime code & place on stack.
                bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
                // Utilize assembly so that memory regions can be reused across hashes.
                assembly {
                    // Retrieve the free memory pointer and place on the stack.
                    let hashArrPtr := mload(FreeMemoryPointerSlot)
                    // Get the pointer to the offers array.
                    let offerArrPtr := mload(
                        add(orderParameters, OrderParameters_offer_head_offset)
                    )
                    // Load the length.
                    let offerLength := mload(offerArrPtr)
                    // Set the pointer to the first offer's head.
                    offerArrPtr := add(offerArrPtr, OneWord)
                    // Iterate over the offer items.
                    for {
                        let i := 0
                    } lt(i, offerLength) {
                        i := add(i, 1)
                    } {
                        // Read the pointer to the offer data and subtract one word
                        // to get typeHash pointer.
                        let ptr := sub(mload(offerArrPtr), OneWord)
                        // Read the current value before the offer data.
                        let value := mload(ptr)
                        // Write the type hash to the previous word.
                        mstore(ptr, typeHash)
                        // Take the EIP712 hash and store it in the hash array.
                        mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size))
                        // Restore the previous word.
                        mstore(ptr, value)
                        // Increment the array pointers by one word.
                        offerArrPtr := add(offerArrPtr, OneWord)
                        hashArrPtr := add(hashArrPtr, OneWord)
                    }
                    // Derive the offer hash using the hashes of each item.
                    offerHash := keccak256(
                        mload(FreeMemoryPointerSlot),
                        shl(OneWordShift, offerLength)
                    )
                }
                // Declare a variable for the derived hash of the consideration array.
                bytes32 considerationHash;
                // Read consideration item typehash from runtime code & place on stack.
                typeHash = _CONSIDERATION_ITEM_TYPEHASH;
                // Utilize assembly so that memory regions can be reused across hashes.
                assembly {
                    // Retrieve the free memory pointer and place on the stack.
                    let hashArrPtr := mload(FreeMemoryPointerSlot)
                    // Get the pointer to the consideration array.
                    let considerationArrPtr := add(
                        mload(
                            add(
                                orderParameters,
                                OrderParameters_consideration_head_offset
                            )
                        ),
                        OneWord
                    )
                    // Iterate over the consideration items (not including tips).
                    for {
                        let i := 0
                    } lt(i, originalConsiderationLength) {
                        i := add(i, 1)
                    } {
                        // Read the pointer to the consideration data and subtract one
                        // word to get typeHash pointer.
                        let ptr := sub(mload(considerationArrPtr), OneWord)
                        // Read the current value before the consideration data.
                        let value := mload(ptr)
                        // Write the type hash to the previous word.
                        mstore(ptr, typeHash)
                        // Take the EIP712 hash and store it in the hash array.
                        mstore(
                            hashArrPtr,
                            keccak256(ptr, EIP712_ConsiderationItem_size)
                        )
                        // Restore the previous word.
                        mstore(ptr, value)
                        // Increment the array pointers by one word.
                        considerationArrPtr := add(considerationArrPtr, OneWord)
                        hashArrPtr := add(hashArrPtr, OneWord)
                    }
                    // Derive the consideration hash using the hashes of each item.
                    considerationHash := keccak256(
                        mload(FreeMemoryPointerSlot),
                        shl(OneWordShift, originalConsiderationLength)
                    )
                }
                // Read order item EIP-712 typehash from runtime code & place on stack.
                typeHash = _ORDER_TYPEHASH;
                // Utilize assembly to access derived hashes & other arguments directly.
                assembly {
                    // Retrieve pointer to the region located just behind parameters.
                    let typeHashPtr := sub(orderParameters, OneWord)
                    // Store the value at that pointer location to restore later.
                    let previousValue := mload(typeHashPtr)
                    // Store the order item EIP-712 typehash at the typehash location.
                    mstore(typeHashPtr, typeHash)
                    // Retrieve the pointer for the offer array head.
                    let offerHeadPtr := add(
                        orderParameters,
                        OrderParameters_offer_head_offset
                    )
                    // Retrieve the data pointer referenced by the offer head.
                    let offerDataPtr := mload(offerHeadPtr)
                    // Store the offer hash at the retrieved memory location.
                    mstore(offerHeadPtr, offerHash)
                    // Retrieve the pointer for the consideration array head.
                    let considerationHeadPtr := add(
                        orderParameters,
                        OrderParameters_consideration_head_offset
                    )
                    // Retrieve the data pointer referenced by the consideration head.
                    let considerationDataPtr := mload(considerationHeadPtr)
                    // Store the consideration hash at the retrieved memory location.
                    mstore(considerationHeadPtr, considerationHash)
                    // Retrieve the pointer for the counter.
                    let counterPtr := add(
                        orderParameters,
                        OrderParameters_counter_offset
                    )
                    // Store the counter at the retrieved memory location.
                    mstore(counterPtr, counter)
                    // Derive the order hash using the full range of order parameters.
                    orderHash := keccak256(typeHashPtr, EIP712_Order_size)
                    // Restore the value previously held at typehash pointer location.
                    mstore(typeHashPtr, previousValue)
                    // Restore offer data pointer at the offer head pointer location.
                    mstore(offerHeadPtr, offerDataPtr)
                    // Restore consideration data pointer at the consideration head ptr.
                    mstore(considerationHeadPtr, considerationDataPtr)
                    // Restore consideration item length at the counter pointer.
                    mstore(counterPtr, originalConsiderationLength)
                }
            }
            /**
             * @dev Internal view function to derive the address of a given conduit
             *      using a corresponding conduit key.
             *
             * @param conduitKey A bytes32 value indicating what corresponding conduit,
             *                   if any, to source token approvals from. This value is
             *                   the "salt" parameter supplied by the deployer (i.e. the
             *                   conduit controller) when deploying the given conduit.
             *
             * @return conduit The address of the conduit associated with the given
             *                 conduit key.
             */
            function _deriveConduit(
                bytes32 conduitKey
            ) internal view returns (address conduit) {
                // Read conduit controller address from runtime and place on the stack.
                address conduitController = address(_CONDUIT_CONTROLLER);
                // Read conduit creation code hash from runtime and place on the stack.
                bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;
                // Leverage scratch space to perform an efficient hash.
                assembly {
                    // Retrieve the free memory pointer; it will be replaced afterwards.
                    let freeMemoryPointer := mload(FreeMemoryPointerSlot)
                    // Place the control character and the conduit controller in scratch
                    // space; note that eleven bytes at the beginning are left unused.
                    mstore(0, or(MaskOverByteTwelve, conduitController))
                    // Place the conduit key in the next region of scratch space.
                    mstore(OneWord, conduitKey)
                    // Place conduit creation code hash in free memory pointer location.
                    mstore(TwoWords, conduitCreationCodeHash)
                    // Derive conduit by hashing and applying a mask over last 20 bytes.
                    conduit := and(
                        // Hash the relevant region.
                        keccak256(
                            // The region starts at memory pointer 11.
                            Create2AddressDerivation_ptr,
                            // The region is 85 bytes long (1 + 20 + 32 + 32).
                            Create2AddressDerivation_length
                        ),
                        // The address equals the last twenty bytes of the hash.
                        MaskOverLastTwentyBytes
                    )
                    // Restore the free memory pointer.
                    mstore(FreeMemoryPointerSlot, freeMemoryPointer)
                }
            }
            /**
             * @dev Internal view function to get the EIP-712 domain separator. If the
             *      chainId matches the chainId set on deployment, the cached domain
             *      separator will be returned; otherwise, it will be derived from
             *      scratch.
             *
             * @return The domain separator.
             */
            function _domainSeparator() internal view returns (bytes32) {
                return
                    block.chainid == _CHAIN_ID
                        ? _DOMAIN_SEPARATOR
                        : _deriveDomainSeparator();
            }
            /**
             * @dev Internal view function to retrieve configuration information for
             *      this contract.
             *
             * @return The contract version.
             * @return The domain separator for this contract.
             * @return The conduit Controller set for this contract.
             */
            function _information()
                internal
                view
                returns (
                    string memory /* version */,
                    bytes32 /* domainSeparator */,
                    address /* conduitController */
                )
            {
                // Derive the domain separator.
                bytes32 domainSeparator = _domainSeparator();
                // Declare variable as immutables cannot be accessed within assembly.
                address conduitController = address(_CONDUIT_CONTROLLER);
                // Return the version, domain separator, and conduit controller.
                assembly {
                    mstore(information_version_offset, information_version_cd_offset)
                    mstore(information_domainSeparator_offset, domainSeparator)
                    mstore(information_conduitController_offset, conduitController)
                    mstore(information_versionLengthPtr, information_versionWithLength)
                    return(information_version_offset, information_length)
                }
            }
            /**
             * @dev Internal pure function to efficiently derive an digest to sign for
             *      an order in accordance with EIP-712.
             *
             * @param domainSeparator The domain separator.
             * @param orderHash       The order hash.
             *
             * @return value The hash.
             */
            function _deriveEIP712Digest(
                bytes32 domainSeparator,
                bytes32 orderHash
            ) internal pure returns (bytes32 value) {
                // Leverage scratch space to perform an efficient hash.
                assembly {
                    // Place the EIP-712 prefix at the start of scratch space.
                    mstore(0, EIP_712_PREFIX)
                    // Place the domain separator in the next region of scratch space.
                    mstore(EIP712_DomainSeparator_offset, domainSeparator)
                    // Place the order hash in scratch space, spilling into the first
                    // two bytes of the free memory pointer — this should never be set
                    // as memory cannot be expanded to that size, and will be zeroed out
                    // after the hash is performed.
                    mstore(EIP712_OrderHash_offset, orderHash)
                    // Hash the relevant region (65 bytes).
                    value := keccak256(0, EIP712_DigestPayload_size)
                    // Clear out the dirtied bits in the memory pointer.
                    mstore(EIP712_OrderHash_offset, 0)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ConsiderationEventsAndErrors
        } from "seaport-types/src/interfaces/ConsiderationEventsAndErrors.sol";
        import { ReentrancyGuard } from "./ReentrancyGuard.sol";
        import {
            Counter_blockhash_shift,
            OneWord,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        /**
         * @title CounterManager
         * @author 0age
         * @notice CounterManager contains a storage mapping and related functionality
         *         for retrieving and incrementing a per-offerer counter.
         */
        contract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard {
            // Only orders signed using an offerer's current counter are fulfillable.
            mapping(address => uint256) private _counters;
            /**
             * @dev Internal function to cancel all orders from a given offerer in bulk
             *      by incrementing a counter by a large, quasi-random interval. Note
             *      that only the offerer may increment the counter. Note that the
             *      counter is incremented by a large, quasi-random interval, which
             *      makes it infeasible to "activate" signed orders by incrementing the
             *      counter.  This activation functionality can be achieved instead with
             *      restricted orders or contract orders.
             *
             * @return newCounter The new counter.
             */
            function _incrementCounter() internal returns (uint256 newCounter) {
                // Ensure that the reentrancy guard is not currently set.
                _assertNonReentrant();
                // Utilize assembly to access counters storage mapping directly. Skip
                // overflow check as counter cannot be incremented that far.
                assembly {
                    // Use second half of previous block hash as a quasi-random number.
                    let quasiRandomNumber := shr(
                        Counter_blockhash_shift,
                        blockhash(sub(number(), 1))
                    )
                    // Write the caller to scratch space.
                    mstore(0, caller())
                    // Write the storage slot for _counters to scratch space.
                    mstore(OneWord, _counters.slot)
                    // Derive the storage pointer for the counter value.
                    let storagePointer := keccak256(0, TwoWords)
                    // Derive new counter value using random number and original value.
                    newCounter := add(quasiRandomNumber, sload(storagePointer))
                    // Store the updated counter value.
                    sstore(storagePointer, newCounter)
                }
                // Emit an event containing the new counter.
                emit CounterIncremented(newCounter, msg.sender);
            }
            /**
             * @dev Internal view function to retrieve the current counter for a given
             *      offerer.
             *
             * @param offerer The offerer in question.
             *
             * @return currentCounter The current counter.
             */
            function _getCounter(
                address offerer
            ) internal view returns (uint256 currentCounter) {
                // Return the counter for the supplied offerer.
                currentCounter = _counters[offerer];
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title SignatureVerificationErrors
         * @author 0age
         * @notice SignatureVerificationErrors contains all errors related to signature
         *         verification.
         */
        interface SignatureVerificationErrors {
            /**
             * @dev Revert with an error when a signature that does not contain a v
             *      value of 27 or 28 has been supplied.
             *
             * @param v The invalid v value.
             */
            error BadSignatureV(uint8 v);
            /**
             * @dev Revert with an error when the signer recovered by the supplied
             *      signature does not match the offerer or an allowed EIP-1271 signer
             *      as specified by the offerer in the event they are a contract.
             */
            error InvalidSigner();
            /**
             * @dev Revert with an error when a signer cannot be recovered from the
             *      supplied signature.
             */
            error InvalidSignature();
            /**
             * @dev Revert with an error when an EIP-1271 call to an account fails.
             */
            error BadContractSignature();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ConduitControllerInterface
        } from "seaport-types/src/interfaces/ConduitControllerInterface.sol";
        import {
            ConsiderationEventsAndErrors
        } from "seaport-types/src/interfaces/ConsiderationEventsAndErrors.sol";
        import {
            BulkOrder_Typehash_Height_One,
            BulkOrder_Typehash_Height_Two,
            BulkOrder_Typehash_Height_Three,
            BulkOrder_Typehash_Height_Four,
            BulkOrder_Typehash_Height_Five,
            BulkOrder_Typehash_Height_Six,
            BulkOrder_Typehash_Height_Seven,
            BulkOrder_Typehash_Height_Eight,
            BulkOrder_Typehash_Height_Nine,
            BulkOrder_Typehash_Height_Ten,
            BulkOrder_Typehash_Height_Eleven,
            BulkOrder_Typehash_Height_Twelve,
            BulkOrder_Typehash_Height_Thirteen,
            BulkOrder_Typehash_Height_Fourteen,
            BulkOrder_Typehash_Height_Fifteen,
            BulkOrder_Typehash_Height_Sixteen,
            BulkOrder_Typehash_Height_Seventeen,
            BulkOrder_Typehash_Height_Eighteen,
            BulkOrder_Typehash_Height_Nineteen,
            BulkOrder_Typehash_Height_Twenty,
            BulkOrder_Typehash_Height_TwentyOne,
            BulkOrder_Typehash_Height_TwentyTwo,
            BulkOrder_Typehash_Height_TwentyThree,
            BulkOrder_Typehash_Height_TwentyFour,
            EIP712_domainData_chainId_offset,
            EIP712_domainData_nameHash_offset,
            EIP712_domainData_size,
            EIP712_domainData_verifyingContract_offset,
            EIP712_domainData_versionHash_offset,
            FreeMemoryPointerSlot,
            NameLengthPtr,
            NameWithLength,
            OneWord,
            Slot0x80,
            ThreeWords,
            ZeroSlot
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import { ConsiderationDecoder } from "./ConsiderationDecoder.sol";
        import { ConsiderationEncoder } from "./ConsiderationEncoder.sol";
        /**
         * @title ConsiderationBase
         * @author 0age
         * @notice ConsiderationBase contains immutable constants and constructor logic.
         */
        contract ConsiderationBase is
            ConsiderationDecoder,
            ConsiderationEncoder,
            ConsiderationEventsAndErrors
        {
            // Precompute hashes, original chainId, and domain separator on deployment.
            bytes32 internal immutable _NAME_HASH;
            bytes32 internal immutable _VERSION_HASH;
            bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH;
            bytes32 internal immutable _OFFER_ITEM_TYPEHASH;
            bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH;
            bytes32 internal immutable _ORDER_TYPEHASH;
            uint256 internal immutable _CHAIN_ID;
            bytes32 internal immutable _DOMAIN_SEPARATOR;
            // Allow for interaction with the conduit controller.
            ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;
            // Cache the conduit creation code hash used by the conduit controller.
            bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
            /**
             * @dev Derive and set hashes, reference chainId, and associated domain
             *      separator during deployment.
             *
             * @param conduitController A contract that deploys conduits, or proxies
             *                          that may optionally be used to transfer approved
             *                          ERC20/721/1155 tokens.
             */
            constructor(address conduitController) {
                // Derive name and version hashes alongside required EIP-712 typehashes.
                (
                    _NAME_HASH,
                    _VERSION_HASH,
                    _EIP_712_DOMAIN_TYPEHASH,
                    _OFFER_ITEM_TYPEHASH,
                    _CONSIDERATION_ITEM_TYPEHASH,
                    _ORDER_TYPEHASH
                ) = _deriveTypehashes();
                // Store the current chainId and derive the current domain separator.
                _CHAIN_ID = block.chainid;
                _DOMAIN_SEPARATOR = _deriveDomainSeparator();
                // Set the supplied conduit controller.
                _CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);
                // Retrieve the conduit creation code hash from the supplied controller.
                (_CONDUIT_CREATION_CODE_HASH, ) = (
                    _CONDUIT_CONTROLLER.getConduitCodeHashes()
                );
            }
            /**
             * @dev Internal view function to derive the EIP-712 domain separator.
             *
             * @return domainSeparator The derived domain separator.
             */
            function _deriveDomainSeparator()
                internal
                view
                returns (bytes32 domainSeparator)
            {
                bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH;
                bytes32 nameHash = _NAME_HASH;
                bytes32 versionHash = _VERSION_HASH;
                // Leverage scratch space and other memory to perform an efficient hash.
                assembly {
                    // Retrieve the free memory pointer; it will be replaced afterwards.
                    let freeMemoryPointer := mload(FreeMemoryPointerSlot)
                    // Retrieve value at 0x80; it will also be replaced afterwards.
                    let slot0x80 := mload(Slot0x80)
                    // Place typehash, name hash, and version hash at start of memory.
                    mstore(0, typehash)
                    mstore(EIP712_domainData_nameHash_offset, nameHash)
                    mstore(EIP712_domainData_versionHash_offset, versionHash)
                    // Place chainId in the next memory location.
                    mstore(EIP712_domainData_chainId_offset, chainid())
                    // Place the address of this contract in the next memory location.
                    mstore(EIP712_domainData_verifyingContract_offset, address())
                    // Hash relevant region of memory to derive the domain separator.
                    domainSeparator := keccak256(0, EIP712_domainData_size)
                    // Restore the free memory pointer.
                    mstore(FreeMemoryPointerSlot, freeMemoryPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                    // Restore the value at 0x80.
                    mstore(Slot0x80, slot0x80)
                }
            }
            /**
             * @dev Internal pure function to retrieve the default name of this
             *      contract and return.
             *
             * @return The name of this contract.
             */
            function _name() internal pure virtual returns (string memory) {
                // Return the name of the contract.
                assembly {
                    // First element is the offset for the returned string. Offset the
                    // value in memory by one word so that the free memory pointer will
                    // be overwritten by the next write.
                    mstore(OneWord, OneWord)
                    // Name is right padded, so it touches the length which is left
                    // padded. This enables writing both values at once. The free memory
                    // pointer will be overwritten in the process.
                    mstore(NameLengthPtr, NameWithLength)
                    // Standard ABI encoding pads returned data to the nearest word. Use
                    // the already empty zero slot memory region for this purpose and
                    // return the final name string, offset by the original single word.
                    return(OneWord, ThreeWords)
                }
            }
            /**
             * @dev Internal pure function to retrieve the default name of this contract
             *      as a string that can be used internally.
             *
             * @return The name of this contract.
             */
            function _nameString() internal pure virtual returns (string memory) {
                // Return the name of the contract.
                return "Consideration";
            }
            /**
             * @dev Internal pure function to derive required EIP-712 typehashes and
             *      other hashes during contract creation.
             *
             * @return nameHash                  The hash of the name of the contract.
             * @return versionHash               The hash of the version string of the
             *                                   contract.
             * @return eip712DomainTypehash      The primary EIP-712 domain typehash.
             * @return offerItemTypehash         The EIP-712 typehash for OfferItem
             *                                   types.
             * @return considerationItemTypehash The EIP-712 typehash for
             *                                   ConsiderationItem types.
             * @return orderTypehash             The EIP-712 typehash for Order types.
             */
            function _deriveTypehashes()
                internal
                pure
                returns (
                    bytes32 nameHash,
                    bytes32 versionHash,
                    bytes32 eip712DomainTypehash,
                    bytes32 offerItemTypehash,
                    bytes32 considerationItemTypehash,
                    bytes32 orderTypehash
                )
            {
                // Derive hash of the name of the contract.
                nameHash = keccak256(bytes(_nameString()));
                // Derive hash of the version string of the contract.
                versionHash = keccak256(bytes("1.6"));
                // Construct the OfferItem type string.
                bytes memory offerItemTypeString = bytes(
                    "OfferItem("
                    "uint8 itemType,"
                    "address token,"
                    "uint256 identifierOrCriteria,"
                    "uint256 startAmount,"
                    "uint256 endAmount"
                    ")"
                );
                // Construct the ConsiderationItem type string.
                bytes memory considerationItemTypeString = bytes(
                    "ConsiderationItem("
                    "uint8 itemType,"
                    "address token,"
                    "uint256 identifierOrCriteria,"
                    "uint256 startAmount,"
                    "uint256 endAmount,"
                    "address recipient"
                    ")"
                );
                // Construct the OrderComponents type string, not including the above.
                bytes memory orderComponentsPartialTypeString = bytes(
                    "OrderComponents("
                    "address offerer,"
                    "address zone,"
                    "OfferItem[] offer,"
                    "ConsiderationItem[] consideration,"
                    "uint8 orderType,"
                    "uint256 startTime,"
                    "uint256 endTime,"
                    "bytes32 zoneHash,"
                    "uint256 salt,"
                    "bytes32 conduitKey,"
                    "uint256 counter"
                    ")"
                );
                // Construct the primary EIP-712 domain type string.
                eip712DomainTypehash = keccak256(
                    bytes(
                        "EIP712Domain("
                        "string name,"
                        "string version,"
                        "uint256 chainId,"
                        "address verifyingContract"
                        ")"
                    )
                );
                // Derive the OfferItem type hash using the corresponding type string.
                offerItemTypehash = keccak256(offerItemTypeString);
                // Derive ConsiderationItem type hash using corresponding type string.
                considerationItemTypehash = keccak256(considerationItemTypeString);
                bytes memory orderTypeString = bytes.concat(
                    orderComponentsPartialTypeString,
                    considerationItemTypeString,
                    offerItemTypeString
                );
                // Derive OrderItem type hash via combination of relevant type strings.
                orderTypehash = keccak256(orderTypeString);
            }
            /**
             * @dev Internal pure function to look up one of twenty-four potential bulk
             *      order typehash constants based on the height of the bulk order tree.
             *      Note that values between one and twenty-four are supported, which is
             *      enforced by _isValidBulkOrderSize.
             *
             * @param _treeHeight The height of the bulk order tree. The value must be
             *                    between one and twenty-four.
             *
             * @return _typeHash The EIP-712 typehash for the bulk order type with the
             *                   given height.
             */
            function _lookupBulkOrderTypehash(
                uint256 _treeHeight
            ) internal pure returns (bytes32 _typeHash) {
                // Utilize assembly to efficiently retrieve correct bulk order typehash.
                assembly {
                    // Use a Yul function to enable use of the `leave` keyword
                    // to stop searching once the appropriate type hash is found.
                    function lookupTypeHash(treeHeight) -> typeHash {
                        // Handle tree heights one through eight.
                        if lt(treeHeight, 9) {
                            // Handle tree heights one through four.
                            if lt(treeHeight, 5) {
                                // Handle tree heights one and two.
                                if lt(treeHeight, 3) {
                                    // Utilize branchless logic to determine typehash.
                                    typeHash := ternary(
                                        eq(treeHeight, 1),
                                        BulkOrder_Typehash_Height_One,
                                        BulkOrder_Typehash_Height_Two
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle height three and four via branchless logic.
                                typeHash := ternary(
                                    eq(treeHeight, 3),
                                    BulkOrder_Typehash_Height_Three,
                                    BulkOrder_Typehash_Height_Four
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle tree height five and six.
                            if lt(treeHeight, 7) {
                                // Utilize branchless logic to determine typehash.
                                typeHash := ternary(
                                    eq(treeHeight, 5),
                                    BulkOrder_Typehash_Height_Five,
                                    BulkOrder_Typehash_Height_Six
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle height seven and eight via branchless logic.
                            typeHash := ternary(
                                eq(treeHeight, 7),
                                BulkOrder_Typehash_Height_Seven,
                                BulkOrder_Typehash_Height_Eight
                            )
                            // Exit the function once typehash has been located.
                            leave
                        }
                        // Handle tree height nine through sixteen.
                        if lt(treeHeight, 17) {
                            // Handle tree height nine through twelve.
                            if lt(treeHeight, 13) {
                                // Handle tree height nine and ten.
                                if lt(treeHeight, 11) {
                                    // Utilize branchless logic to determine typehash.
                                    typeHash := ternary(
                                        eq(treeHeight, 9),
                                        BulkOrder_Typehash_Height_Nine,
                                        BulkOrder_Typehash_Height_Ten
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle height eleven and twelve via branchless logic.
                                typeHash := ternary(
                                    eq(treeHeight, 11),
                                    BulkOrder_Typehash_Height_Eleven,
                                    BulkOrder_Typehash_Height_Twelve
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle tree height thirteen and fourteen.
                            if lt(treeHeight, 15) {
                                // Utilize branchless logic to determine typehash.
                                typeHash := ternary(
                                    eq(treeHeight, 13),
                                    BulkOrder_Typehash_Height_Thirteen,
                                    BulkOrder_Typehash_Height_Fourteen
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle height fifteen and sixteen via branchless logic.
                            typeHash := ternary(
                                eq(treeHeight, 15),
                                BulkOrder_Typehash_Height_Fifteen,
                                BulkOrder_Typehash_Height_Sixteen
                            )
                            // Exit the function once typehash has been located.
                            leave
                        }
                        // Handle tree height seventeen through twenty.
                        if lt(treeHeight, 21) {
                            // Handle tree height seventeen and eighteen.
                            if lt(treeHeight, 19) {
                                // Utilize branchless logic to determine typehash.
                                typeHash := ternary(
                                    eq(treeHeight, 17),
                                    BulkOrder_Typehash_Height_Seventeen,
                                    BulkOrder_Typehash_Height_Eighteen
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle height nineteen and twenty via branchless logic.
                            typeHash := ternary(
                                eq(treeHeight, 19),
                                BulkOrder_Typehash_Height_Nineteen,
                                BulkOrder_Typehash_Height_Twenty
                            )
                            // Exit the function once typehash has been located.
                            leave
                        }
                        // Handle tree height twenty-one and twenty-two.
                        if lt(treeHeight, 23) {
                            // Utilize branchless logic to determine typehash.
                            typeHash := ternary(
                                eq(treeHeight, 21),
                                BulkOrder_Typehash_Height_TwentyOne,
                                BulkOrder_Typehash_Height_TwentyTwo
                            )
                            // Exit the function once typehash has been located.
                            leave
                        }
                        // Handle height twenty-three & twenty-four w/ branchless logic.
                        typeHash := ternary(
                            eq(treeHeight, 23),
                            BulkOrder_Typehash_Height_TwentyThree,
                            BulkOrder_Typehash_Height_TwentyFour
                        )
                        // Exit the function once typehash has been located.
                        leave
                    }
                    // Implement ternary conditional using branchless logic.
                    function ternary(cond, ifTrue, ifFalse) -> c {
                        c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue)))
                    }
                    // Look up the typehash using the supplied tree height.
                    _typeHash := lookupTypeHash(_treeHeight)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        import {
            OrderParameters,
            ReceivedItem,
            SpentItem
        } from "../lib/ConsiderationStructs.sol";
        /**
         * @title ConsiderationEventsAndErrors
         * @author 0age
         * @notice ConsiderationEventsAndErrors contains all events and errors.
         */
        interface ConsiderationEventsAndErrors {
            /**
             * @dev Emit an event whenever an order is successfully fulfilled.
             *
             * @param orderHash     The hash of the fulfilled order.
             * @param offerer       The offerer of the fulfilled order.
             * @param zone          The zone of the fulfilled order.
             * @param recipient     The recipient of each spent item on the fulfilled
             *                      order, or the null address if there is no specific
             *                      fulfiller (i.e. the order is part of a group of
             *                      orders). Defaults to the caller unless explicitly
             *                      specified otherwise by the fulfiller.
             * @param offer         The offer items spent as part of the order.
             * @param consideration The consideration items received as part of the
             *                      order along with the recipients of each item.
             */
            event OrderFulfilled(
                bytes32 orderHash,
                address indexed offerer,
                address indexed zone,
                address recipient,
                SpentItem[] offer,
                ReceivedItem[] consideration
            );
            /**
             * @dev Emit an event whenever an order is successfully cancelled.
             *
             * @param orderHash The hash of the cancelled order.
             * @param offerer   The offerer of the cancelled order.
             * @param zone      The zone of the cancelled order.
             */
            event OrderCancelled(
                bytes32 orderHash,
                address indexed offerer,
                address indexed zone
            );
            /**
             * @dev Emit an event whenever an order is explicitly validated. Note that
             *      this event will not be emitted on partial fills even though they do
             *      validate the order as part of partial fulfillment.
             *
             * @param orderHash        The hash of the validated order.
             * @param orderParameters  The parameters of the validated order.
             */
            event OrderValidated(bytes32 orderHash, OrderParameters orderParameters);
            /**
             * @dev Emit an event whenever one or more orders are matched using either
             *      matchOrders or matchAdvancedOrders.
             *
             * @param orderHashes The order hashes of the matched orders.
             */
            event OrdersMatched(bytes32[] orderHashes);
            /**
             * @dev Emit an event whenever a counter for a given offerer is incremented.
             *
             * @param newCounter The new counter for the offerer.
             * @param offerer    The offerer in question.
             */
            event CounterIncremented(uint256 newCounter, address indexed offerer);
            /**
             * @dev Revert with an error when attempting to fill an order that has
             *      already been fully filled.
             *
             * @param orderHash The order hash on which a fill was attempted.
             */
            error OrderAlreadyFilled(bytes32 orderHash);
            /**
             * @dev Revert with an error when attempting to fill an order outside the
             *      specified start time and end time.
             *
             * @param startTime The time at which the order becomes active.
             * @param endTime   The time at which the order becomes inactive.
             */
            error InvalidTime(uint256 startTime, uint256 endTime);
            /**
             * @dev Revert with an error when attempting to fill an order referencing an
             *      invalid conduit (i.e. one that has not been deployed).
             */
            error InvalidConduit(bytes32 conduitKey, address conduit);
            /**
             * @dev Revert with an error when an order is supplied for fulfillment with
             *      a consideration array that is shorter than the original array.
             */
            error MissingOriginalConsiderationItems();
            /**
             * @dev Revert with an error when an order is validated and the length of
             *      the consideration array is not equal to the supplied total original
             *      consideration items value. This error is also thrown when contract
             *      orders supply a total original consideration items value that does
             *      not match the supplied consideration array length.
             */
            error ConsiderationLengthNotEqualToTotalOriginal();
            /**
             * @dev Revert with an error when a call to a conduit fails with revert data
             *      that is too expensive to return.
             */
            error InvalidCallToConduit(address conduit);
            /**
             * @dev Revert with an error if a consideration amount has not been fully
             *      zeroed out after applying all fulfillments.
             *
             * @param orderIndex         The index of the order with the consideration
             *                           item with a shortfall.
             * @param considerationIndex The index of the consideration item on the
             *                           order.
             * @param shortfallAmount    The unfulfilled consideration amount.
             */
            error ConsiderationNotMet(
                uint256 orderIndex,
                uint256 considerationIndex,
                uint256 shortfallAmount
            );
            /**
             * @dev Revert with an error when insufficient native tokens are supplied as
             *      part of msg.value when fulfilling orders.
             */
            error InsufficientNativeTokensSupplied();
            /**
             * @dev Revert with an error when a native token transfer reverts.
             */
            error NativeTokenTransferGenericFailure(address account, uint256 amount);
            /**
             * @dev Revert with an error when a partial fill is attempted on an order
             *      that does not specify partial fill support in its order type.
             */
            error PartialFillsNotEnabledForOrder();
            /**
             * @dev Revert with an error when attempting to fill an order that has been
             *      cancelled.
             *
             * @param orderHash The hash of the cancelled order.
             */
            error OrderIsCancelled(bytes32 orderHash);
            /**
             * @dev Revert with an error when attempting to fill a basic order that has
             *      been partially filled.
             *
             * @param orderHash The hash of the partially used order.
             */
            error OrderPartiallyFilled(bytes32 orderHash);
            /**
             * @dev Revert with an error when attempting to cancel an order as a caller
             *      other than the indicated offerer or zone or when attempting to
             *      cancel a contract order.
             */
            error CannotCancelOrder();
            /**
             * @dev Revert with an error when supplying a fraction with a value of zero
             *      for the numerator or denominator, or one where the numerator exceeds
             *      the denominator.
             */
            error BadFraction();
            /**
             * @dev Revert with an error when a caller attempts to supply callvalue to a
             *      non-payable basic order route or does not supply any callvalue to a
             *      payable basic order route.
             */
            error InvalidMsgValue(uint256 value);
            /**
             * @dev Revert with an error when attempting to fill a basic order using
             *      calldata not produced by default ABI encoding.
             */
            error InvalidBasicOrderParameterEncoding();
            /**
             * @dev Revert with an error when attempting to fulfill any number of
             *      available orders when none are fulfillable.
             */
            error NoSpecifiedOrdersAvailable();
            /**
             * @dev Revert with an error when attempting to fulfill an order with an
             *      offer for a native token outside of matching orders.
             */
            error InvalidNativeOfferItem();
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            ReentrancyErrors
        } from "seaport-types/src/interfaces/ReentrancyErrors.sol";
        import { LowLevelHelpers } from "./LowLevelHelpers.sol";
        import {
            _revertInvalidMsgValue,
            _revertNoReentrantCalls
        } from "seaport-types/src/lib/ConsiderationErrors.sol";
        import {
            _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_SSTORE,
            _ENTERED_SSTORE,
            _NOT_ENTERED_SSTORE,
            _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_TSTORE,
            _ENTERED_TSTORE,
            _NOT_ENTERED_TSTORE,
            _TSTORE_ENABLED_SSTORE,
            _REENTRANCY_GUARD_SLOT,
            _TLOAD_TEST_PAYLOAD,
            _TLOAD_TEST_PAYLOAD_OFFSET,
            _TLOAD_TEST_PAYLOAD_LENGTH
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            InvalidMsgValue_error_selector,
            InvalidMsgValue_error_length,
            InvalidMsgValue_error_value_ptr,
            NoReentrantCalls_error_selector,
            NoReentrantCalls_error_length,
            Error_selector_offset
        } from "seaport-types/src/lib/ConsiderationErrorConstants.sol";
        /**
         * @title ReentrancyGuard
         * @author 0age
         * @notice ReentrancyGuard contains a storage variable (or a transient storage
         *         variable in EVM environments that support it once activated) and
         *         related functionality for protecting against reentrancy.
         */
        contract ReentrancyGuard is ReentrancyErrors, LowLevelHelpers {
            // Declare an immutable variable to store the initial TSTORE support status.
            bool private immutable _tstoreInitialSupport;
            // Declare an immutable variable to store the tstore test contract address.
            address private immutable _tloadTestContract;
            /**
             * @dev Initialize the reentrancy guard during deployment. This involves
             *      attempting to deploy a contract that utilizes TLOAD as part of the
             *      contract construction bytecode, and configuring initial support for
             *      using TSTORE in place of SSTORE for the reentrancy lock based on the
             *      result.
             */
            constructor() {
                // Deploy the contract testing TLOAD support and store the address.
                address tloadTestContract = _prepareTloadTest();
                // Ensure the deployment was successful.
                if (tloadTestContract == address(0)) {
                    revert TloadTestContractDeploymentFailed();
                }
                // Determine if TSTORE is supported.
                bool tstoreInitialSupport = _testTload(tloadTestContract);
                // Store the result as an immutable.
                _tstoreInitialSupport = tstoreInitialSupport;
                // Set the address of the deployed TLOAD test contract as an immutable.
                _tloadTestContract = tloadTestContract;
                // If not using TSTORE (where _NOT_ENTERED_TSTORE = 0), set initial
                // sentinel value (where _NOT_ENTERED_SSTORE = 1).
                if (!tstoreInitialSupport) {
                    // Initialize storage for the reentrancy guard in a cleared state.
                    assembly {
                        sstore(_REENTRANCY_GUARD_SLOT, _NOT_ENTERED_SSTORE)
                    }
                }
            }
            /**
             * @dev External function to activate TSTORE usage for the reentrancy guard.
             *      Does not need to be called if TSTORE is supported from deployment,
             *      and only needs to be called once. Reverts if TSTORE has already been
             *      activated, if the opcode is not available, or if the reentrancy
             *      guard is currently set.
             */
            function __activateTstore() external {
                // Determine if TSTORE can potentially be activated. If it has already
                // been activated, or if the reentrancy guard is currently set, then
                // it cannot be activated.
                bool tstoreActivatable;
                assembly {
                    tstoreActivatable := eq(
                        sload(_REENTRANCY_GUARD_SLOT),
                        _NOT_ENTERED_SSTORE
                    )
                }
                // Revert if TSTORE is already activated or not activatable.
                if (_tstoreInitialSupport || !tstoreActivatable) {
                    revert TStoreAlreadyActivated();
                }
                // Determine if TSTORE can be activated and revert if not.
                if (!_testTload(_tloadTestContract)) {
                    revert TStoreNotSupported();
                }
                // Mark TSTORE as activated.
                assembly {
                    sstore(_REENTRANCY_GUARD_SLOT, _TSTORE_ENABLED_SSTORE)
                }
            }
            /**
             * @dev Internal function to ensure that a sentinel value for the reentrancy
             *      guard is not currently set and, if not, to set a sentinel value for
             *      the reentrancy guard based on whether or not native tokens may be
             *      received during execution or not.
             *
             * @param acceptNativeTokens A boolean indicating whether native tokens may
             *                           be received during execution or not.
             */
            function _setReentrancyGuard(bool acceptNativeTokens) internal {
                // Place immutable variable on the stack access within inline assembly.
                bool tstoreInitialSupport = _tstoreInitialSupport;
                // Utilize assembly to set the reentrancy guard based on tstore support.
                assembly {
                    // "Loop" over three possible cases for setting the reentrancy guard
                    // based on tstore support and state, exiting once the respective
                    // state has been identified and a corresponding guard has been set.
                    for {} 1 {} {
                        // 1: handle case where tstore is supported from the start.
                        if tstoreInitialSupport {
                            // Ensure that the reentrancy guard is not already set.
                            if tload(_REENTRANCY_GUARD_SLOT) {
                                // Store left-padded selector with push4,
                                // mem[28:32] = selector
                                mstore(0, NoReentrantCalls_error_selector)
                                // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                                revert(
                                    Error_selector_offset,
                                    NoReentrantCalls_error_length
                                )
                            }
                            // Set the reentrancy guard. A value of 1 indicates that
                            // native tokens may not be accepted during execution,
                            // whereas a value of 2 indicates that they will be accepted
                            // (returning any remaining native tokens to the caller).
                            tstore(
                                _REENTRANCY_GUARD_SLOT,
                                add(_ENTERED_TSTORE, acceptNativeTokens)
                            )
                            // Exit the loop.
                            break
                        }
                        // Retrieve the reentrancy guard sentinel value.
                        let reentrancyGuard := sload(_REENTRANCY_GUARD_SLOT)
                        // 2: handle tstore support that was activated post-deployment.
                        if iszero(reentrancyGuard) {
                            // Ensure that the reentrancy guard is not already set.
                            if tload(_REENTRANCY_GUARD_SLOT) {
                                // Store left-padded selector with push4,
                                // mem[28:32] = selector
                                mstore(0, NoReentrantCalls_error_selector)
                                // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                                revert(
                                    Error_selector_offset,
                                    NoReentrantCalls_error_length
                                )
                            }
                            // Set the reentrancy guard. A value of 1 indicates that
                            // native tokens may not be accepted during execution,
                            // whereas a value of 2 indicates that they will be accepted
                            // (returning any remaining native tokens to the caller).
                            tstore(
                                _REENTRANCY_GUARD_SLOT,
                                add(_ENTERED_TSTORE, acceptNativeTokens)
                            )
                            // Exit the loop.
                            break
                        }
                        // 3: handle case where tstore support has not been activated.
                        // Ensure that the reentrancy guard is not already set.
                        if iszero(eq(reentrancyGuard, _NOT_ENTERED_SSTORE)) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, NoReentrantCalls_error_selector)
                            // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                            revert(Error_selector_offset, NoReentrantCalls_error_length)
                        }
                        // Set the reentrancy guard. A value of 2 indicates that native
                        // tokens may not be accepted during execution, whereas a value
                        // of 3 indicates that they will be accepted (with any remaining
                        // native tokens returned to the caller).
                        sstore(
                            _REENTRANCY_GUARD_SLOT,
                            add(_ENTERED_SSTORE, acceptNativeTokens)
                        )
                        // Exit the loop.
                        break
                    }
                }
            }
            /**
             * @dev Internal function to unset the reentrancy guard sentinel value.
             */
            function _clearReentrancyGuard() internal {
                // Place immutable variable on the stack access within inline assembly.
                bool tstoreInitialSupport = _tstoreInitialSupport;
                // Utilize assembly to clear reentrancy guard based on tstore support.
                assembly {
                    // "Loop" over three possible cases for clearing reentrancy guard
                    // based on tstore support and state, exiting once the respective
                    // state has been identified and corresponding guard cleared.
                    for {} 1 {} {
                        // 1: handle case where tstore is supported from the start.
                        if tstoreInitialSupport {
                            // Clear the reentrancy guard.
                            tstore(_REENTRANCY_GUARD_SLOT, _NOT_ENTERED_TSTORE)
                            // Exit the loop.
                            break
                        }
                        // Retrieve the reentrancy guard sentinel value.
                        let reentrancyGuard := sload(_REENTRANCY_GUARD_SLOT)
                        // 2: handle tstore support that was activated post-deployment.
                        if iszero(reentrancyGuard) {
                            // Clear the reentrancy guard.
                            tstore(_REENTRANCY_GUARD_SLOT, _NOT_ENTERED_TSTORE)
                            // Exit the loop.
                            break
                        }
                        // 3: handle case where tstore support has not been activated.
                        // Clear the reentrancy guard.
                        sstore(_REENTRANCY_GUARD_SLOT, _NOT_ENTERED_SSTORE)
                        // Exit the loop.
                        break
                    }
                }
            }
            /**
             * @dev Internal view function to ensure that a sentinel value for the
             *      reentrancy guard is not currently set.
             */
            function _assertNonReentrant() internal view {
                // Place immutable variable on the stack access within inline assembly.
                bool tstoreInitialSupport = _tstoreInitialSupport;
                // Utilize assembly to check reentrancy guard based on tstore support.
                assembly {
                    // 1: handle case where tstore is supported from the start.
                    if tstoreInitialSupport {
                        // Ensure that the reentrancy guard is not currently set.
                        if tload(_REENTRANCY_GUARD_SLOT) {
                            // Store left-padded selector with push4,
                            // mem[28:32] = selector
                            mstore(0, NoReentrantCalls_error_selector)
                            // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                            revert(Error_selector_offset, NoReentrantCalls_error_length)
                        }
                    }
                    // Handle cases where tstore is not initially supported.
                    if iszero(tstoreInitialSupport) {
                        // Retrieve the reentrancy guard sentinel value.
                        let reentrancyGuard := sload(_REENTRANCY_GUARD_SLOT)
                        // 2: handle tstore support that was activated post-deployment.
                        if iszero(reentrancyGuard) {
                            // Ensure that the reentrancy guard is not currently set.
                            if tload(_REENTRANCY_GUARD_SLOT) {
                                // Store left-padded selector with push4,
                                // mem[28:32] = selector
                                mstore(0, NoReentrantCalls_error_selector)
                                // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                                revert(
                                    Error_selector_offset,
                                    NoReentrantCalls_error_length
                                )
                            }
                        }
                        // 3: handle case where tstore support has not been activated.
                        // Ensure that the reentrancy guard is not currently set.
                        if gt(reentrancyGuard, _NOT_ENTERED_SSTORE) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, NoReentrantCalls_error_selector)
                            // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                            revert(Error_selector_offset, NoReentrantCalls_error_length)
                        }
                    }
                }
            }
            /**
             * @dev Internal view function to ensure that the sentinel value indicating
             *      native tokens may be received during execution is currently set.
             */
            function _assertAcceptingNativeTokens() internal view {
                // Place immutable variable on the stack access within inline assembly.
                bool tstoreInitialSupport = _tstoreInitialSupport;
                // Utilize assembly to check reentrancy guard based on tstore support.
                assembly {
                    // 1: handle case where tstore is supported from the start.
                    if tstoreInitialSupport {
                        // Ensure reentrancy guard is set to accept native tokens.
                        if iszero(
                            eq(
                                tload(_REENTRANCY_GUARD_SLOT),
                                _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_TSTORE
                            )
                        ) {
                            // Store left-padded selector with push4,
                            // mem[28:32] = selector
                            mstore(0, InvalidMsgValue_error_selector)
                            // Store argument.
                            mstore(InvalidMsgValue_error_value_ptr, callvalue())
                            // revert(abi.encodeWithSignature(
                            //   "InvalidMsgValue(uint256)", value)
                            // )
                            revert(Error_selector_offset, InvalidMsgValue_error_length)
                        }
                    }
                    // Handle cases where tstore is not initially supported.
                    if iszero(tstoreInitialSupport) {
                        // Retrieve the reentrancy guard sentinel value.
                        let reentrancyGuard := sload(_REENTRANCY_GUARD_SLOT)
                        // 2: handle tstore support that was activated post-deployment.
                        if iszero(reentrancyGuard) {
                            // Ensure reentrancy guard is set to accept native tokens.
                            if iszero(
                                eq(
                                    tload(_REENTRANCY_GUARD_SLOT),
                                    _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_TSTORE
                                )
                            ) {
                                // Store left-padded selector with push4,
                                // mem[28:32] = selector
                                mstore(0, InvalidMsgValue_error_selector)
                                // Store argument.
                                mstore(InvalidMsgValue_error_value_ptr, callvalue())
                                // revert(abi.encodeWithSignature(
                                //   "InvalidMsgValue(uint256)", value)
                                // )
                                revert(
                                    Error_selector_offset,
                                    InvalidMsgValue_error_length
                                )
                            }
                        }
                        // 3: handle case where tstore support has not been activated.
                        // Ensure reentrancy guard is set to accepting native tokens.
                        if and(
                            iszero(iszero(reentrancyGuard)),
                            iszero(
                                eq(
                                    reentrancyGuard,
                                    _ENTERED_AND_ACCEPTING_NATIVE_TOKENS_SSTORE
                                )
                            )
                        ) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, InvalidMsgValue_error_selector)
                            // Store argument.
                            mstore(InvalidMsgValue_error_value_ptr, callvalue())
                            // revert(abi.encodeWithSignature(
                            //   "InvalidMsgValue(uint256)", value)
                            // )
                            revert(Error_selector_offset, InvalidMsgValue_error_length)
                        }
                    }
                }
            }
            /**
             * @dev Private function to deploy a test contract that utilizes TLOAD as
             *      part of its fallback logic.
             */
            function _prepareTloadTest() private returns (address contractAddress) {
                // Utilize assembly to deploy a contract testing TLOAD support.
                assembly {
                    // Write the contract deployment code payload to scratch space.
                    mstore(0, _TLOAD_TEST_PAYLOAD)
                    // Deploy the contract.
                    contractAddress := create(
                        0,
                        _TLOAD_TEST_PAYLOAD_OFFSET,
                        _TLOAD_TEST_PAYLOAD_LENGTH
                    )
                }
            }
            /**
             * @dev Private view function to determine if TSTORE/TLOAD are supported by
             *      the current EVM implementation by attempting to call the test
             *      contract, which utilizes TLOAD as part of its fallback logic.
             */
            function _testTload(
                address tloadTestContract
            ) private view returns (bool ok) {
                // Call the test contract, which will perform a TLOAD test. If the call
                // does not revert, then TLOAD/TSTORE is supported. Do not forward all
                // available gas, as all forwarded gas will be consumed on revert.
                (ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title ConduitControllerInterface
         * @author 0age
         * @notice ConduitControllerInterface contains all external function interfaces,
         *         structs, events, and errors for the conduit controller.
         */
        interface ConduitControllerInterface {
            /**
             * @dev Track the conduit key, current owner, new potential owner, and open
             *      channels for each deployed conduit.
             */
            struct ConduitProperties {
                bytes32 key;
                address owner;
                address potentialOwner;
                address[] channels;
                mapping(address => uint256) channelIndexesPlusOne;
            }
            /**
             * @dev Emit an event whenever a new conduit is created.
             *
             * @param conduit    The newly created conduit.
             * @param conduitKey The conduit key used to create the new conduit.
             */
            event NewConduit(address conduit, bytes32 conduitKey);
            /**
             * @dev Emit an event whenever conduit ownership is transferred.
             *
             * @param conduit       The conduit for which ownership has been
             *                      transferred.
             * @param previousOwner The previous owner of the conduit.
             * @param newOwner      The new owner of the conduit.
             */
            event OwnershipTransferred(
                address indexed conduit,
                address indexed previousOwner,
                address indexed newOwner
            );
            /**
             * @dev Emit an event whenever a conduit owner registers a new potential
             *      owner for that conduit.
             *
             * @param newPotentialOwner The new potential owner of the conduit.
             */
            event PotentialOwnerUpdated(address indexed newPotentialOwner);
            /**
             * @dev Revert with an error when attempting to create a new conduit using a
             *      conduit key where the first twenty bytes of the key do not match the
             *      address of the caller.
             */
            error InvalidCreator();
            /**
             * @dev Revert with an error when attempting to create a new conduit when no
             *      initial owner address is supplied.
             */
            error InvalidInitialOwner();
            /**
             * @dev Revert with an error when attempting to set a new potential owner
             *      that is already set.
             */
            error NewPotentialOwnerAlreadySet(
                address conduit,
                address newPotentialOwner
            );
            /**
             * @dev Revert with an error when attempting to cancel ownership transfer
             *      when no new potential owner is currently set.
             */
            error NoPotentialOwnerCurrentlySet(address conduit);
            /**
             * @dev Revert with an error when attempting to interact with a conduit that
             *      does not yet exist.
             */
            error NoConduit();
            /**
             * @dev Revert with an error when attempting to create a conduit that
             *      already exists.
             */
            error ConduitAlreadyExists(address conduit);
            /**
             * @dev Revert with an error when attempting to update channels or transfer
             *      ownership of a conduit when the caller is not the owner of the
             *      conduit in question.
             */
            error CallerIsNotOwner(address conduit);
            /**
             * @dev Revert with an error when attempting to register a new potential
             *      owner and supplying the null address.
             */
            error NewPotentialOwnerIsZeroAddress(address conduit);
            /**
             * @dev Revert with an error when attempting to claim ownership of a conduit
             *      with a caller that is not the current potential owner for the
             *      conduit in question.
             */
            error CallerIsNotNewPotentialOwner(address conduit);
            /**
             * @dev Revert with an error when attempting to retrieve a channel using an
             *      index that is out of range.
             */
            error ChannelOutOfRange(address conduit);
            /**
             * @notice Deploy a new conduit using a supplied conduit key and assigning
             *         an initial owner for the deployed conduit. Note that the first
             *         twenty bytes of the supplied conduit key must match the caller
             *         and that a new conduit cannot be created if one has already been
             *         deployed using the same conduit key.
             *
             * @param conduitKey   The conduit key used to deploy the conduit. Note that
             *                     the first twenty bytes of the conduit key must match
             *                     the caller of this contract.
             * @param initialOwner The initial owner to set for the new conduit.
             *
             * @return conduit The address of the newly deployed conduit.
             */
            function createConduit(
                bytes32 conduitKey,
                address initialOwner
            ) external returns (address conduit);
            /**
             * @notice Open or close a channel on a given conduit, thereby allowing the
             *         specified account to execute transfers against that conduit.
             *         Extreme care must be taken when updating channels, as malicious
             *         or vulnerable channels can transfer any ERC20, ERC721 and ERC1155
             *         tokens where the token holder has granted the conduit approval.
             *         Only the owner of the conduit in question may call this function.
             *
             * @param conduit The conduit for which to open or close the channel.
             * @param channel The channel to open or close on the conduit.
             * @param isOpen  A boolean indicating whether to open or close the channel.
             */
            function updateChannel(
                address conduit,
                address channel,
                bool isOpen
            ) external;
            /**
             * @notice Initiate conduit ownership transfer by assigning a new potential
             *         owner for the given conduit. Once set, the new potential owner
             *         may call `acceptOwnership` to claim ownership of the conduit.
             *         Only the owner of the conduit in question may call this function.
             *
             * @param conduit The conduit for which to initiate ownership transfer.
             * @param newPotentialOwner The new potential owner of the conduit.
             */
            function transferOwnership(
                address conduit,
                address newPotentialOwner
            ) external;
            /**
             * @notice Clear the currently set potential owner, if any, from a conduit.
             *         Only the owner of the conduit in question may call this function.
             *
             * @param conduit The conduit for which to cancel ownership transfer.
             */
            function cancelOwnershipTransfer(address conduit) external;
            /**
             * @notice Accept ownership of a supplied conduit. Only accounts that the
             *         current owner has set as the new potential owner may call this
             *         function.
             *
             * @param conduit The conduit for which to accept ownership.
             */
            function acceptOwnership(address conduit) external;
            /**
             * @notice Retrieve the current owner of a deployed conduit.
             *
             * @param conduit The conduit for which to retrieve the associated owner.
             *
             * @return owner The owner of the supplied conduit.
             */
            function ownerOf(address conduit) external view returns (address owner);
            /**
             * @notice Retrieve the conduit key for a deployed conduit via reverse
             *         lookup.
             *
             * @param conduit The conduit for which to retrieve the associated conduit
             *                key.
             *
             * @return conduitKey The conduit key used to deploy the supplied conduit.
             */
            function getKey(address conduit) external view returns (bytes32 conduitKey);
            /**
             * @notice Derive the conduit associated with a given conduit key and
             *         determine whether that conduit exists (i.e. whether it has been
             *         deployed).
             *
             * @param conduitKey The conduit key used to derive the conduit.
             *
             * @return conduit The derived address of the conduit.
             * @return exists  A boolean indicating whether the derived conduit has been
             *                 deployed or not.
             */
            function getConduit(
                bytes32 conduitKey
            ) external view returns (address conduit, bool exists);
            /**
             * @notice Retrieve the potential owner, if any, for a given conduit. The
             *         current owner may set a new potential owner via
             *         `transferOwnership` and that owner may then accept ownership of
             *         the conduit in question via `acceptOwnership`.
             *
             * @param conduit The conduit for which to retrieve the potential owner.
             *
             * @return potentialOwner The potential owner, if any, for the conduit.
             */
            function getPotentialOwner(
                address conduit
            ) external view returns (address potentialOwner);
            /**
             * @notice Retrieve the status (either open or closed) of a given channel on
             *         a conduit.
             *
             * @param conduit The conduit for which to retrieve the channel status.
             * @param channel The channel for which to retrieve the status.
             *
             * @return isOpen The status of the channel on the given conduit.
             */
            function getChannelStatus(
                address conduit,
                address channel
            ) external view returns (bool isOpen);
            /**
             * @notice Retrieve the total number of open channels for a given conduit.
             *
             * @param conduit The conduit for which to retrieve the total channel count.
             *
             * @return totalChannels The total number of open channels for the conduit.
             */
            function getTotalChannels(
                address conduit
            ) external view returns (uint256 totalChannels);
            /**
             * @notice Retrieve an open channel at a specific index for a given conduit.
             *         Note that the index of a channel can change as a result of other
             *         channels being closed on the conduit.
             *
             * @param conduit      The conduit for which to retrieve the open channel.
             * @param channelIndex The index of the channel in question.
             *
             * @return channel The open channel, if any, at the specified channel index.
             */
            function getChannel(
                address conduit,
                uint256 channelIndex
            ) external view returns (address channel);
            /**
             * @notice Retrieve all open channels for a given conduit. Note that calling
             *         this function for a conduit with many channels will revert with
             *         an out-of-gas error.
             *
             * @param conduit The conduit for which to retrieve open channels.
             *
             * @return channels An array of open channels on the given conduit.
             */
            function getChannels(
                address conduit
            ) external view returns (address[] memory channels);
            /**
             * @dev Retrieve the conduit creation code and runtime code hashes.
             */
            function getConduitCodeHashes()
                external
                view
                returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.24;
        import {
            AdvancedOrder,
            ConsiderationItem,
            CriteriaResolver,
            Fulfillment,
            FulfillmentComponent,
            OfferItem,
            Order,
            OrderParameters,
            ReceivedItem
        } from "seaport-types/src/lib/ConsiderationStructs.sol";
        import {
            AdvancedOrder_denominator_offset,
            AdvancedOrder_extraData_offset,
            AdvancedOrder_fixed_segment_0,
            AdvancedOrder_head_size,
            AdvancedOrder_numerator_offset,
            AdvancedOrder_signature_offset,
            AdvancedOrderPlusOrderParameters_head_size,
            Common_amount_offset,
            Common_endAmount_offset,
            Common_identifier_offset,
            Common_token_offset,
            ConsiderationItem_recipient_offset,
            ConsiderationItem_size_with_head_pointer,
            ConsiderationItem_size,
            CriteriaResolver_criteriaProof_offset,
            CriteriaResolver_fixed_segment_0,
            CriteriaResolver_head_size,
            ThreeWords,
            FreeMemoryPointerSlot,
            Fulfillment_considerationComponents_offset,
            Fulfillment_head_size,
            FulfillmentComponent_mem_tail_size_shift,
            FulfillmentComponent_mem_tail_size,
            generateOrder_maximum_returned_array_length,
            OfferItem_size_with_head_pointer,
            OfferItem_size,
            OneWord,
            OneWordShift,
            OnlyFullWordMask,
            Order_head_size,
            Order_signature_offset,
            OrderComponents_OrderParameters_common_head_size,
            OrderParameters_consideration_head_offset,
            OrderParameters_head_size,
            OrderParameters_offer_head_offset,
            OrderParameters_totalOriginalConsiderationItems_offset,
            ReceivedItem_recipient_offset,
            ReceivedItem_size,
            ReceivedItem_size_excluding_recipient,
            SpentItem_size_shift,
            SpentItem_size,
            ThirtyOneBytes,
            TwoWords
        } from "seaport-types/src/lib/ConsiderationConstants.sol";
        import {
            CalldataPointer,
            malloc,
            MemoryPointer,
            OffsetOrLengthMask
        } from "seaport-types/src/helpers/PointerLibraries.sol";
        contract ConsiderationDecoder {
            /**
             * @dev Takes a bytes array from calldata and copies it into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the bytes array in
             *                    calldata which contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the bytes array in
             *                    memory which contains the length of the array.
             */
            function _decodeBytes(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                assembly {
                    // Get the current free memory pointer.
                    mPtrLength := mload(FreeMemoryPointerSlot)
                    // Derive the size of the bytes array, rounding up to nearest word
                    // and adding a word for the length field. Note: masking
                    // `calldataload(cdPtrLength)` is redundant here.
                    let size := add(
                        and(
                            add(calldataload(cdPtrLength), ThirtyOneBytes),
                            OnlyFullWordMask
                        ),
                        OneWord
                    )
                    // Copy bytes from calldata into memory based on pointers and size.
                    calldatacopy(mPtrLength, cdPtrLength, size)
                    // Store the masked value in memory. Note: the value of `size` is at
                    // least 32, meaning the calldatacopy above will at least write to
                    // `[mPtrLength, mPtrLength + 32)`.
                    mstore(
                        mPtrLength,
                        and(calldataload(cdPtrLength), OffsetOrLengthMask)
                    )
                    // Update free memory pointer based on the size of the bytes array.
                    mstore(FreeMemoryPointerSlot, add(mPtrLength, size))
                }
            }
            /**
             * @dev Takes an offer array from calldata and copies it into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the offer array
             *                    in calldata which contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the offer array in
             *                    memory which contains the length of the array.
             */
            function _decodeOffer(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                assembly {
                    // Retrieve length of array, masking to prevent potential overflow.
                    let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                    // Get the current free memory pointer.
                    mPtrLength := mload(FreeMemoryPointerSlot)
                    // Write the array length to memory.
                    mstore(mPtrLength, arrLength)
                    // Derive the head by adding one word to the length pointer.
                    let mPtrHead := add(mPtrLength, OneWord)
                    // Derive the tail by adding one word per element (note that structs
                    // are written to memory with an offset per struct element).
                    let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                    // Track the next tail, beginning with the initial tail value.
                    let mPtrTailNext := mPtrTail
                    // Copy all offer array data into memory at the tail pointer.
                    calldatacopy(
                        mPtrTail,
                        add(cdPtrLength, OneWord),
                        mul(arrLength, OfferItem_size)
                    )
                    // Track the next head pointer, starting with initial head value.
                    let mPtrHeadNext := mPtrHead
                    // Iterate over each head pointer until it reaches the tail.
                    for {
                    } lt(mPtrHeadNext, mPtrTail) {
                    } {
                        // Write the next tail pointer to next head pointer in memory.
                        mstore(mPtrHeadNext, mPtrTailNext)
                        // Increment the next head pointer by one word.
                        mPtrHeadNext := add(mPtrHeadNext, OneWord)
                        // Increment the next tail pointer by the size of an offer item.
                        mPtrTailNext := add(mPtrTailNext, OfferItem_size)
                    }
                    // Update free memory pointer to allocate memory up to end of tail.
                    mstore(FreeMemoryPointerSlot, mPtrTailNext)
                }
            }
            /**
             * @dev Takes a consideration array from calldata and copies it into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the consideration
             *                    array in calldata which contains the length of the
             *                    array.
             *
             * @return mPtrLength A memory pointer to the start of the consideration
             *                    array in memory which contains the length of the
             *                    array.
             */
            function _decodeConsideration(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                assembly {
                    // Retrieve length of array, masking to prevent potential overflow.
                    let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                    // Get the current free memory pointer.
                    mPtrLength := mload(FreeMemoryPointerSlot)
                    // Write the array length to memory.
                    mstore(mPtrLength, arrLength)
                    // Derive the head by adding one word to the length pointer.
                    let mPtrHead := add(mPtrLength, OneWord)
                    // Derive the tail by adding one word per element (note that structs
                    // are written to memory with an offset per struct element).
                    let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                    // Track the next tail, beginning with the initial tail value.
                    let mPtrTailNext := mPtrTail
                    // Copy all consideration array data into memory at tail pointer.
                    calldatacopy(
                        mPtrTail,
                        add(cdPtrLength, OneWord),
                        mul(arrLength, ConsiderationItem_size)
                    )
                    // Track the next head pointer, starting with initial head value.
                    let mPtrHeadNext := mPtrHead
                    // Iterate over each head pointer until it reaches the tail.
                    for {
                    } lt(mPtrHeadNext, mPtrTail) {
                    } {
                        // Write the next tail pointer to next head pointer in memory.
                        mstore(mPtrHeadNext, mPtrTailNext)
                        // Increment the next head pointer by one word.
                        mPtrHeadNext := add(mPtrHeadNext, OneWord)
                        // Increment next tail pointer by size of a consideration item.
                        mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size)
                    }
                    // Update free memory pointer to allocate memory up to end of tail.
                    mstore(FreeMemoryPointerSlot, mPtrTailNext)
                }
            }
            /**
             * @dev Takes a calldata pointer and memory pointer and copies a referenced
             *      OrderParameters struct and associated offer and consideration data
             *      to memory.
             *
             * @param cdPtr A calldata pointer for the OrderParameters struct.
             * @param mPtr A memory pointer to the OrderParameters struct head.
             */
            function _decodeOrderParametersTo(
                CalldataPointer cdPtr,
                MemoryPointer mPtr
            ) internal pure {
                // Copy the full OrderParameters head from calldata to memory.
                cdPtr.copy(mPtr, OrderParameters_head_size);
                // Resolve the offer calldata offset, use that to decode and copy offer
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.offset(OrderParameters_offer_head_offset).write(
                    _decodeOffer(cdPtr.pptrOffset(OrderParameters_offer_head_offset))
                );
                // Resolve consideration calldata offset, use that to copy consideration
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.offset(OrderParameters_consideration_head_offset).write(
                    _decodeConsideration(
                        cdPtr.pptrOffset(OrderParameters_consideration_head_offset)
                    )
                );
            }
            /**
             * @dev Takes a calldata pointer to an OrderParameters struct and copies the
             *      decoded struct to memory.
             *
             * @param cdPtr A calldata pointer for the OrderParameters struct.
             *
             * @return mPtr A memory pointer to the OrderParameters struct head.
             */
            function _decodeOrderParameters(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate required memory for the OrderParameters head (offer and
                // consideration are allocated independently).
                mPtr = malloc(OrderParameters_head_size);
                // Decode and copy the order parameters to the newly allocated memory.
                _decodeOrderParametersTo(cdPtr, mPtr);
            }
            /**
             * @dev Takes a calldata pointer to an Order struct and copies the decoded
             *      struct to memory.
             *
             * @param cdPtr A calldata pointer for the Order struct.
             *
             * @return mPtr A memory pointer to the Order struct head.
             */
            function _decodeOrder(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate required memory for the Order head (OrderParameters and
                // signature are allocated independently).
                mPtr = malloc(Order_head_size);
                // Resolve OrderParameters calldata offset, use it to decode and copy
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.write(_decodeOrderParameters(cdPtr.pptr()));
                // Resolve signature calldata offset, use that to decode and copy from
                // calldata, and write resultant memory offset to head in memory.
                mPtr.offset(Order_signature_offset).write(
                    _decodeBytes(cdPtr.pptrOffset(Order_signature_offset))
                );
            }
            /**
             * @dev Takes a calldata pointer to an AdvancedOrder struct and copies the
             *      decoded struct to memory.
             *
             * @param cdPtr A calldata pointer for the AdvancedOrder struct.
             *
             * @return mPtr A memory pointer to the AdvancedOrder struct head.
             */
            function _decodeAdvancedOrder(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate memory for AdvancedOrder head and OrderParameters head.
                mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size);
                // Use numerator + denominator calldata offset to decode and copy
                // from calldata and write resultant memory offset to head in memory.
                cdPtr.offset(AdvancedOrder_numerator_offset).copy(
                    mPtr.offset(AdvancedOrder_numerator_offset),
                    AdvancedOrder_fixed_segment_0
                );
                // Get pointer to memory immediately after advanced order.
                MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size);
                // Write pptr for advanced order parameters to memory.
                mPtr.write(mPtrParameters);
                // Resolve OrderParameters calldata pointer & write to allocated region.
                _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters);
                // Resolve signature calldata offset, use that to decode and copy from
                // calldata, and write resultant memory offset to head in memory.
                mPtr.offset(AdvancedOrder_signature_offset).write(
                    _decodeBytes(cdPtr.pptrOffset(AdvancedOrder_signature_offset))
                );
                // Resolve extraData calldata offset, use that to decode and copy from
                // calldata, and write resultant memory offset to head in memory.
                mPtr.offset(AdvancedOrder_extraData_offset).write(
                    _decodeBytes(cdPtr.pptrOffset(AdvancedOrder_extraData_offset))
                );
            }
            /**
             * @dev Allocates a single word of empty bytes in memory and returns the
             *      pointer to that memory region.
             *
             * @return mPtr The memory pointer to the new empty word in memory.
             */
            function _getEmptyBytesOrArray()
                internal
                pure
                returns (MemoryPointer mPtr)
            {
                mPtr = malloc(OneWord);
                mPtr.write(0);
            }
            /**
             * @dev Takes a calldata pointer to an Order struct and copies the decoded
             *      struct to memory as an AdvancedOrder.
             *
             * @param cdPtr A calldata pointer for the Order struct.
             *
             * @return mPtr A memory pointer to the AdvancedOrder struct head.
             */
            function _decodeOrderAsAdvancedOrder(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate memory for AdvancedOrder head and OrderParameters head.
                mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size);
                // Get pointer to memory immediately after advanced order.
                MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size);
                // Write pptr for advanced order parameters.
                mPtr.write(mPtrParameters);
                // Resolve OrderParameters calldata pointer & write to allocated region.
                _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters);
                // Write default Order numerator and denominator values (i.e. 1/1).
                mPtr.offset(AdvancedOrder_numerator_offset).write(1);
                mPtr.offset(AdvancedOrder_denominator_offset).write(1);
                // Resolve signature calldata offset, use that to decode and copy from
                // calldata, and write resultant memory offset to head in memory.
                mPtr.offset(AdvancedOrder_signature_offset).write(
                    _decodeBytes(cdPtr.pptrOffset(Order_signature_offset))
                );
                // Resolve extraData calldata offset, use that to decode and copy from
                // calldata, and write resultant memory offset to head in memory.
                mPtr.offset(AdvancedOrder_extraData_offset).write(
                    _getEmptyBytesOrArray()
                );
            }
            /**
             * @dev Takes a calldata pointer to an array of Order structs and copies the
             *      decoded array to memory as an array of AdvancedOrder structs.
             *
             * @param cdPtrLength A calldata pointer to the start of the orders array in
             *                    calldata which contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the array of advanced
             *                    orders in memory which contains length of the array.
             */
            function _decodeOrdersAsAdvancedOrders(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve Order calldata offset, use it to decode and copy from
                        // calldata, and write resultant AdvancedOrder offset to memory.
                        mPtrHead.offset(offset).write(
                            _decodeOrderAsAdvancedOrder(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes a calldata pointer to a criteria proof, or an array bytes32
             *      types, and copies the decoded proof to memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the criteria proof
             *                    in calldata which contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the criteria proof
             *                    in memory which contains length of the array.
             */
            function _decodeCriteriaProof(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive array size based on one word per array element and length.
                    uint256 arrSize = (arrLength + 1) << OneWordShift;
                    // Allocate memory equal to the array size.
                    mPtrLength = malloc(arrSize);
                    // Copy the array from calldata into memory.
                    cdPtrLength.copy(mPtrLength, arrSize);
                }
            }
            /**
             * @dev Takes a calldata pointer to a CriteriaResolver struct and copies the
             *      decoded struct to memory.
             *
             * @param cdPtr A calldata pointer for the CriteriaResolver struct.
             *
             * @return mPtr A memory pointer to the CriteriaResolver struct head.
             */
            function _decodeCriteriaResolver(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate required memory for the CriteriaResolver head (the criteria
                // proof bytes32 array is allocated independently).
                mPtr = malloc(CriteriaResolver_head_size);
                // Decode and copy order index, side, index, and identifier from
                // calldata and write resultant memory offset to head in memory.
                cdPtr.copy(mPtr, CriteriaResolver_fixed_segment_0);
                // Resolve criteria proof calldata offset, use it to decode and copy
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.offset(CriteriaResolver_criteriaProof_offset).write(
                    _decodeCriteriaProof(
                        cdPtr.pptrOffset(CriteriaResolver_criteriaProof_offset)
                    )
                );
            }
            /**
             * @dev Takes an array of criteria resolvers from calldata and copies it
             *      into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the criteria
             *                    resolver array in calldata which contains the length
             *                    of the array.
             *
             * @return mPtrLength A memory pointer to the start of the criteria resolver
             *                    array in memory which contains the length of the
             *                    array.
             */
            function _decodeCriteriaResolvers(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve CriteriaResolver calldata offset, use it to decode
                        // and copy from calldata, and write resultant memory offset.
                        mPtrHead.offset(offset).write(
                            _decodeCriteriaResolver(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes an array of orders from calldata and copies it into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the orders array in
             *                    calldata which contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the orders array
             *                    in memory which contains the length of the array.
             */
            function _decodeOrders(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve Order calldata offset, use it to decode and copy
                        // from calldata, and write resultant memory offset.
                        mPtrHead.offset(offset).write(
                            _decodeOrder(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes an array of fulfillment components from calldata and copies it
             *      into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the fulfillment
             *                    components array in calldata which contains the length
             *                    of the array.
             *
             * @return mPtrLength A memory pointer to the start of the fulfillment
             *                    components array in memory which contains the length
             *                    of the array.
             */
            function _decodeFulfillmentComponents(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                assembly {
                    let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                    // Get the current free memory pointer.
                    mPtrLength := mload(FreeMemoryPointerSlot)
                    mstore(mPtrLength, arrLength)
                    let mPtrHead := add(mPtrLength, OneWord)
                    let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                    let mPtrTailNext := mPtrTail
                    calldatacopy(
                        mPtrTail,
                        add(cdPtrLength, OneWord),
                        shl(FulfillmentComponent_mem_tail_size_shift, arrLength)
                    )
                    let mPtrHeadNext := mPtrHead
                    for {
                    } lt(mPtrHeadNext, mPtrTail) {
                    } {
                        mstore(mPtrHeadNext, mPtrTailNext)
                        mPtrHeadNext := add(mPtrHeadNext, OneWord)
                        mPtrTailNext := add(
                            mPtrTailNext,
                            FulfillmentComponent_mem_tail_size
                        )
                    }
                    // Update the free memory pointer.
                    mstore(FreeMemoryPointerSlot, mPtrTailNext)
                }
            }
            /**
             * @dev Takes a nested array of fulfillment components from calldata and
             *      copies it into memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the nested
             *                    fulfillment components array in calldata which
             *                    contains the length of the array.
             *
             * @return mPtrLength A memory pointer to the start of the nested
             *                    fulfillment components array in memory which
             *                    contains the length of the array.
             */
            function _decodeNestedFulfillmentComponents(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve FulfillmentComponents array calldata offset, use it
                        // to decode and copy from calldata, and write memory offset.
                        mPtrHead.offset(offset).write(
                            _decodeFulfillmentComponents(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes an array of advanced orders from calldata and copies it into
             *      memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the advanced orders
             *                    array in calldata which contains the length of the
             *                    array.
             *
             * @return mPtrLength A memory pointer to the start of the advanced orders
             *                    array in memory which contains the length of the
             *                    array.
             */
            function _decodeAdvancedOrders(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve AdvancedOrder calldata offset, use it to decode and
                        // copy from calldata, and write resultant memory offset.
                        mPtrHead.offset(offset).write(
                            _decodeAdvancedOrder(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes a calldata pointer to a Fulfillment struct and copies the
             *      decoded struct to memory.
             *
             * @param cdPtr A calldata pointer for the Fulfillment struct.
             *
             * @return mPtr A memory pointer to the Fulfillment struct head.
             */
            function _decodeFulfillment(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate required memory for the Fulfillment head (the fulfillment
                // components arrays are allocated independently).
                mPtr = malloc(Fulfillment_head_size);
                // Resolve offerComponents calldata offset, use it to decode and copy
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.write(_decodeFulfillmentComponents(cdPtr.pptr()));
                // Resolve considerationComponents calldata offset, use it to decode and
                // copy from calldata, and write resultant memory offset to memory head.
                mPtr.offset(Fulfillment_considerationComponents_offset).write(
                    _decodeFulfillmentComponents(
                        cdPtr.pptrOffset(Fulfillment_considerationComponents_offset)
                    )
                );
            }
            /**
             * @dev Takes an array of fulfillments from calldata and copies it into
             *      memory.
             *
             * @param cdPtrLength A calldata pointer to the start of the fulfillments
             *                    array in calldata which contains the length of the
             *                    array.
             *
             * @return mPtrLength A memory pointer to the start of the fulfillments
             *                    array in memory which contains the length of the
             *                    array.
             */
            function _decodeFulfillments(
                CalldataPointer cdPtrLength
            ) internal pure returns (MemoryPointer mPtrLength) {
                // Retrieve length of array, masking to prevent potential overflow.
                uint256 arrLength = cdPtrLength.readMaskedUint256();
                unchecked {
                    // Derive offset to the tail based on one word per array element.
                    uint256 tailOffset = arrLength << OneWordShift;
                    // Add one additional word for the length and allocate memory.
                    mPtrLength = malloc(tailOffset + OneWord);
                    // Write the length of the array to memory.
                    mPtrLength.write(arrLength);
                    // Advance to first memory & calldata pointers (e.g. after length).
                    MemoryPointer mPtrHead = mPtrLength.next();
                    CalldataPointer cdPtrHead = cdPtrLength.next();
                    // Iterate over each pointer, word by word, until tail is reached.
                    for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                        // Resolve Fulfillment calldata offset, use it to decode and
                        // copy from calldata, and write resultant memory offset.
                        mPtrHead.offset(offset).write(
                            _decodeFulfillment(cdPtrHead.pptrOffset(offset))
                        );
                    }
                }
            }
            /**
             * @dev Takes a calldata pointer to an OrderComponents struct and copies the
             *      decoded struct to memory as an OrderParameters struct (with the
             *      totalOriginalConsiderationItems value set equal to the length of the
             *      supplied consideration array).
             *
             * @param cdPtr A calldata pointer for the OrderComponents struct.
             *
             * @return mPtr A memory pointer to the OrderParameters struct head.
             */
            function _decodeOrderComponentsAsOrderParameters(
                CalldataPointer cdPtr
            ) internal pure returns (MemoryPointer mPtr) {
                // Allocate memory for the OrderParameters head.
                mPtr = malloc(OrderParameters_head_size);
                // Copy the full OrderComponents head from calldata to memory.
                cdPtr.copy(mPtr, OrderComponents_OrderParameters_common_head_size);
                // Resolve the offer calldata offset, use that to decode and copy offer
                // from calldata, and write resultant memory offset to head in memory.
                mPtr.offset(OrderParameters_offer_head_offset).write(
                    _decodeOffer(cdPtr.pptrOffset(OrderParameters_offer_head_offset))
                );
                // Resolve consideration calldata offset, use that to copy consideration
                // from calldata, and write resultant memory offset to head in memory.
                MemoryPointer consideration = _decodeConsideration(
                    cdPtr.pptrOffset(OrderParameters_consideration_head_offset)
                );
                mPtr.offset(OrderParameters_consideration_head_offset).write(
                    consideration
                );
                // Write masked consideration length to totalOriginalConsiderationItems.
                mPtr
                    .offset(OrderParameters_totalOriginalConsiderationItems_offset)
                    .write(consideration.readUint256());
            }
            /**
             * @dev Decodes the returndata from a call to generateOrder, or returns
             *      empty arrays and a boolean signifying that the returndata does not
             *      adhere to a valid encoding scheme if it cannot be decoded. Note
             *      that this function expects that original offer and consideration
             *      item arrays have been modified and repurposed to resemble spent
             *      and received item arrays; specifically, the recipient should be
             *      in the endAmount location on consideration items and the derived
             *      amount should be in the startAmount location for both item types.
             *
             * @return invalidEncoding A boolean signifying whether the returndata has
             *                         an invalid encoding.
             * @return offer           The decoded offer array.
             * @return consideration   The decoded consideration array.
             */
            function _decodeGenerateOrderReturndata(
                MemoryPointer originalOffer,
                MemoryPointer originalConsideration
            )
                internal
                pure
                returns (
                    uint256 invalidEncoding,
                    MemoryPointer offer,
                    MemoryPointer consideration
                )
            {
                assembly {
                    // Check that returndatasize is at least three words:
                    // 1. offerOffset
                    // 2. considerationOffset
                    // 3. offerLength & considerationLength might occupy just one word
                    //    if offerOffset & considerationOffset would point to the same
                    //    offset and the arrays have length 0.
                    invalidEncoding := lt(returndatasize(), ThreeWords)
                    let offsetOffer
                    let offsetConsideration
                    let offerLength
                    let considerationLength
                    // Proceed if enough returndata is present to continue evaluation.
                    if iszero(invalidEncoding) {
                        // Copy first two words of returndata (the offsets to offer and
                        // consideration array lengths) to scratch space.
                        returndatacopy(0, 0, TwoWords)
                        offsetOffer := mload(0)
                        offsetConsideration := mload(OneWord)
                        // If valid length, check that offsets word boundaries are
                        // within returndata.
                        let invalidOfferOffset := gt(
                            add(offsetOffer, OneWord),
                            returndatasize()
                        )
                        let invalidConsiderationOffset := gt(
                            add(offsetConsideration, OneWord),
                            returndatasize()
                        )
                        // Only proceed if length (and thus encoding) is valid so far.
                        invalidEncoding := or(
                            invalidOfferOffset,
                            invalidConsiderationOffset
                        )
                        if iszero(invalidEncoding) {
                            // Copy length of offer array to scratch space.
                            returndatacopy(0, offsetOffer, OneWord)
                            offerLength := mload(0)
                            // Copy length of consideration array to scratch space.
                            returndatacopy(OneWord, offsetConsideration, OneWord)
                            considerationLength := mload(OneWord)
                            {
                                // Derive end offsets for offer & consideration arrays.
                                let offerEndOffset := add(
                                    add(offsetOffer, OneWord),
                                    shl(SpentItem_size_shift, offerLength)
                                )
                                let considerationEndOffset := add(
                                    add(offsetConsideration, OneWord),
                                    mul(ReceivedItem_size, considerationLength)
                                )
                                // Don't continue if either offer or consideration
                                // length exceeds 65535 or if returndatasize is less
                                // than the end offsets.
                                invalidEncoding := or(
                                    gt(
                                        or(offerLength, considerationLength),
                                        generateOrder_maximum_returned_array_length
                                    ),
                                    or(
                                        lt(returndatasize(), offerEndOffset),
                                        lt(returndatasize(), considerationEndOffset)
                                    )
                                )
                                // Set first word of scratch space to 0 so length of
                                // offer/consideration are set to 0 on invalid encoding.
                                mstore(0, 0)
                            }
                        }
                    }
                    if iszero(invalidEncoding) {
                        let invalidSpentItems, invalidReceivedItems
                        offer, invalidSpentItems := copySpentItemsAsOfferItems(
                            originalOffer,
                            add(offsetOffer, OneWord),
                            offerLength
                        )
                        consideration, invalidReceivedItems :=
                            copyReceivedItemsAsConsiderationItems(
                                originalConsideration,
                                add(offsetConsideration, OneWord),
                                considerationLength
                            )
                        invalidEncoding := or(invalidSpentItems, invalidReceivedItems)
                    }
                    function copySpentItemsAsOfferItems(
                        mPtrLengthOriginal,
                        rdPtrHeadSpentItems,
                        length
                    ) -> mPtrLength, invalidSpentItems {
                        // Retrieve the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        // Cache the original offer array length
                        let originalOfferLength := mload(mPtrLengthOriginal)
                        // Allocate memory for the new array.
                        mstore(
                            FreeMemoryPointerSlot,
                            add(
                                mPtrLength,
                                add(
                                    OneWord,
                                    mul(length, OfferItem_size_with_head_pointer)
                                )
                            )
                        )
                        // Write the length of the array to the start of free memory.
                        mstore(mPtrLength, length)
                        // Use offset from length to minimize stack depth.
                        let headOffsetFromLength := OneWord
                        let headSizeWithLength := shl(OneWordShift, add(1, length))
                        let mPtrTailNext := add(mPtrLength, headSizeWithLength)
                        let mPtrTailOriginalNext := add(
                            mPtrLengthOriginal,
                            shl(OneWordShift, add(1, originalOfferLength))
                        )
                        let headSizeToCompareWithLength := shl(
                            OneWordShift,
                            add(1, min(length, originalOfferLength))
                        )
                        // Iterate over each new element with a corresponding original
                        // item. For each original offer item, check that:
                        // - There is a corresponding new spent item.
                        // - The original and new items match with compareItems.
                        // - The new offer item amount >= original amount.
                        invalidSpentItems := gt(originalOfferLength, length)
                        for {
                        } lt(headOffsetFromLength, headSizeToCompareWithLength) {
                        } {
                            // Write the memory pointer to the accompanying head offset.
                            mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext)
                            // Copy itemType, token, identifier and amount.
                            returndatacopy(
                                mPtrTailNext,
                                rdPtrHeadSpentItems,
                                SpentItem_size
                            )
                            let newAmount := mload(
                                add(mPtrTailNext, Common_amount_offset)
                            )
                            // Copy amount to endAmount.
                            mstore(
                                add(mPtrTailNext, Common_endAmount_offset),
                                newAmount
                            )
                            let originalAmount := mload(
                                add(mPtrTailOriginalNext, Common_amount_offset)
                            )
                            invalidSpentItems := or(
                                invalidSpentItems,
                                or(
                                    compareItems(mPtrTailOriginalNext, mPtrTailNext),
                                    gt(originalAmount, newAmount)
                                )
                            )
                            // Update read pointer, next tail pointer for new and
                            // original, and head offset.
                            rdPtrHeadSpentItems := add(
                                rdPtrHeadSpentItems,
                                SpentItem_size
                            )
                            mPtrTailNext := add(mPtrTailNext, OfferItem_size)
                            mPtrTailOriginalNext := add(
                                mPtrTailOriginalNext,
                                OfferItem_size
                            )
                            headOffsetFromLength := add(headOffsetFromLength, OneWord)
                        }
                        // Iterate over each element without corresponding original item
                        for {
                        } lt(headOffsetFromLength, headSizeWithLength) {
                        } {
                            // Write the memory pointer to the accompanying head offset.
                            mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext)
                            // Copy itemType, token, identifier and amount.
                            returndatacopy(
                                mPtrTailNext,
                                rdPtrHeadSpentItems,
                                SpentItem_size
                            )
                            // Copy amount to endAmount.
                            mstore(
                                add(mPtrTailNext, Common_endAmount_offset),
                                mload(add(mPtrTailNext, Common_amount_offset))
                            )
                            // Update read pointer, next tail pointer, and head offset.
                            rdPtrHeadSpentItems := add(
                                rdPtrHeadSpentItems,
                                SpentItem_size
                            )
                            mPtrTailNext := add(mPtrTailNext, OfferItem_size)
                            headOffsetFromLength := add(headOffsetFromLength, OneWord)
                        }
                    }
                    function copyReceivedItemsAsConsiderationItems(
                        mPtrLengthOriginal,
                        rdPtrHeadReceivedItems,
                        length
                    ) -> mPtrLength, invalidReceivedItems {
                        // Retrieve the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        // Cache the original consideration array length
                        let originalConsiderationLength := mload(mPtrLengthOriginal)
                        // Ensure returned array length does not exceed original length.
                        invalidReceivedItems := gt(length, originalConsiderationLength)
                        // Derive the length of the new array in memory, capped by the
                        // original consideration array length.
                        let newLength := min(length, originalConsiderationLength)
                        // Allocate memory for the array. Note that memory does not need
                        // to be allocated for new elements without a corresponding
                        // original item as the new array will be invalid if its length
                        // exceeds the original array length.
                        mstore(
                            FreeMemoryPointerSlot,
                            add(
                                mPtrLength,
                                add(
                                    OneWord,
                                    mul(
                                        newLength,
                                        ConsiderationItem_size_with_head_pointer
                                    )
                                )
                            )
                        )
                        // Write the length of the array to the start of free memory.
                        mstore(mPtrLength, newLength)
                        // Use offset from length to minimize stack depth.
                        let headOffsetFromLength := OneWord
                        let mPtrTailNext := add(
                            mPtrLength,
                            shl(OneWordShift, add(1, newLength))
                        )
                        let mPtrTailOriginalNext := add(
                            mPtrLengthOriginal,
                            shl(OneWordShift, add(1, originalConsiderationLength))
                        )
                        let headSizeToCompareWithLength := shl(
                            OneWordShift,
                            add(1, newLength)
                        )
                        // Iterate over each new element with a corresponding original
                        // item. For each new received item, check that:
                        // - The new & original items match according to compareItems.
                        // - The new consideration item amount <= the original amount.
                        // - The items have the same recipient if original != null.
                        for {
                        } lt(headOffsetFromLength, headSizeToCompareWithLength) {
                        } {
                            // Write the memory pointer to the accompanying head offset.
                            mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext)
                            // Copy itemType, token, identifier, amount and recipient.
                            returndatacopy(
                                mPtrTailNext,
                                rdPtrHeadReceivedItems,
                                ReceivedItem_size
                            )
                            // Copy amount to consideration item's recipient offset.
                            returndatacopy(
                                add(mPtrTailNext, ConsiderationItem_recipient_offset),
                                add(rdPtrHeadReceivedItems, Common_amount_offset),
                                OneWord
                            )
                            // Retrieve both the new and original item amounts.
                            let newAmount := mload(
                                add(mPtrTailNext, Common_amount_offset)
                            )
                            let originalAmount := mload(
                                add(mPtrTailOriginalNext, Common_amount_offset)
                            )
                            // Compare items' item type, token, and identifier, ensure
                            // they have the same recipient and that the new amount is
                            // less than or equal to the original amount. The original
                            // recipient must already be present at the ReceivedItem
                            // recipient offset rather than at the initial
                            // ConsiderationItem recipient offset.
                            invalidReceivedItems := or(
                                invalidReceivedItems,
                                or(
                                    compareItems(mPtrTailOriginalNext, mPtrTailNext),
                                    or(
                                        gt(newAmount, originalAmount),
                                        checkRecipients(
                                            mload(
                                                add(
                                                    mPtrTailOriginalNext,
                                                    ReceivedItem_recipient_offset
                                                )
                                            ),
                                            mload(
                                                add(
                                                    mPtrTailNext,
                                                    ReceivedItem_recipient_offset
                                                )
                                            )
                                        )
                                    )
                                )
                            )
                            // Update read pointer, next tail pointer, and head offset.
                            rdPtrHeadReceivedItems := add(
                                rdPtrHeadReceivedItems,
                                ReceivedItem_size
                            )
                            mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size)
                            mPtrTailOriginalNext := add(
                                mPtrTailOriginalNext,
                                ConsiderationItem_size
                            )
                            headOffsetFromLength := add(headOffsetFromLength, OneWord)
                        }
                        // Note: skip copying new elements without a corresponding
                        // original item as the new array will be invalid if its length
                        // exceeds the original array length.
                    }
                    /**
                     * @dev Yul function to check the compatibility of two offer or
                     *      consideration items for contract orders.  Note that the
                     *      itemType and identifier are reset in cases where criteria is
                     *      equal to 0 (collection-wide or "wildcard" items), which
                     *      means that a contract offerer has full latitude to choose
                     *      any identifier it wants mid-flight, in contrast to the usual
                     *      behavior, where the fulfiller can pick which identifier to
                     *      receive by providing a CriteriaResolver.
                     *
                     * @param originalItem The original offer or consideration item.
                     * @param newItem      The new offer or consideration item.
                     *
                     * @return isInvalid Error buffer indicating whether or not the
                     *                   items are incompatible.
                     */
                    function compareItems(originalItem, newItem) -> isInvalid {
                        let itemType := mload(originalItem)
                        let identifier := mload(
                            add(originalItem, Common_identifier_offset)
                        )
                        // Use returned identifier for criteria-based items with a
                        // criteria value of 0 (collection-wide or "wildcard" items).
                        if and(gt(itemType, 3), iszero(identifier)) {
                            // Replace item type with non-criteria equivalent.
                            itemType := sub(itemType, 2)
                            // Replace identifier with the returned identifier.
                            identifier := mload(add(newItem, Common_identifier_offset))
                        }
                        isInvalid := iszero(
                            and(
                                // originalItem.token == newItem.token &&
                                // originalItem.itemType == newItem.itemType
                                and(
                                    eq(
                                        mload(add(originalItem, Common_token_offset)),
                                        mload(add(newItem, Common_token_offset))
                                    ),
                                    eq(itemType, mload(newItem))
                                ),
                                // originalItem.identifier == newItem.identifier
                                eq(
                                    identifier,
                                    mload(add(newItem, Common_identifier_offset))
                                )
                            )
                        )
                    }
                    /**
                     * @dev Internal pure function to check the compatibility of two
                     *      recipients on consideration items for contract orders. This
                     *      check is skipped if no recipient is originally supplied.
                     *
                     * @param originalRecipient The original consideration item
                     *                          recipient.
                     * @param newRecipient      The new consideration item recipient.
                     *
                     * @return isInvalid Error buffer indicating whether or not the
                     *                   two recipients are incompatible.
                     */
                    function checkRecipients(originalRecipient, newRecipient)
                        -> isInvalid
                    {
                        isInvalid := iszero(
                            or(
                                iszero(originalRecipient),
                                eq(newRecipient, originalRecipient)
                            )
                        )
                    }
                    function min(a, b) -> c {
                        c := add(b, mul(lt(a, b), sub(a, b)))
                    }
                }
            }
            /**
             * @dev Converts a function returning _decodeGenerateOrderReturndata types
             *      into a function returning offer and consideration types.
             *
             * @param inFn The input function, taking no arguments and returning an
             *             error buffer, spent item array, and received item array.
             *
             * @return outFn The output function, taking no arguments and returning an
             *               error buffer, offer array, and consideration array.
             */
            function _convertGetGeneratedOrderResult(
                function(MemoryPointer, MemoryPointer)
                    internal
                    pure
                    returns (uint256, MemoryPointer, MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(OfferItem[] memory, ConsiderationItem[] memory)
                        internal
                        pure
                        returns (
                            uint256,
                            OfferItem[] memory,
                            ConsiderationItem[] memory
                        ) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes
             *      types (e.g. the _transfer function) into a function taking
             *      OfferItem, address, bytes32, and bytes types.
             *
             * @param inFn The input function, taking ReceivedItem, address, bytes32,
             *             and bytes types (e.g. the _transfer function).
             *
             * @return outFn The output function, taking OfferItem, address, bytes32,
             *               and bytes types.
             */
            function _toOfferItemInput(
                function(ReceivedItem memory, address, bytes32, bytes memory)
                    internal inFn
            )
                internal
                pure
                returns (
                    function(OfferItem memory, address, bytes32, bytes memory)
                        internal outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes
             *      types (e.g. the _transfer function) into a function taking
             *      ConsiderationItem, address, bytes32, and bytes types.
             *
             * @param inFn The input function, taking ReceivedItem, address, bytes32,
             *             and bytes types (e.g. the _transfer function).
             *
             * @return outFn The output function, taking ConsiderationItem, address,
             *               bytes32, and bytes types.
             */
            function _toConsiderationItemInput(
                function(ReceivedItem memory, address, bytes32, bytes memory)
                    internal inFn
            )
                internal
                pure
                returns (
                    function(ConsiderationItem memory, address, bytes32, bytes memory)
                        internal outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a bytes type.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a bytes type.
             */
            function _toBytesReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer) internal pure returns (bytes memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      an OrderParameters type.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning an OrderParameters type.
             */
            function _toOrderParametersReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (OrderParameters memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      an AdvancedOrder type.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning an AdvancedOrder type.
             */
            function _toAdvancedOrderReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (AdvancedOrder memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a dynamic array of CriteriaResolver types.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a dynamic array of CriteriaResolver types.
             */
            function _toCriteriaResolversReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (CriteriaResolver[] memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a dynamic array of Order types.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a dynamic array of Order types.
             */
            function _toOrdersReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (Order[] memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a nested dynamic array of dynamic arrays of FulfillmentComponent
             *      types.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a nested dynamic array of dynamic arrays of
             *               FulfillmentComponent types.
             */
            function _toNestedFulfillmentComponentsReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (FulfillmentComponent[][] memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a dynamic array of AdvancedOrder types.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a dynamic array of AdvancedOrder types.
             */
            function _toAdvancedOrdersReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (AdvancedOrder[] memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Converts a function taking a calldata pointer and returning a memory
             *      pointer into a function taking that calldata pointer and returning
             *      a dynamic array of Fulfillment types.
             *
             * @param inFn The input function, taking an arbitrary calldata pointer and
             *             returning an arbitrary memory pointer.
             *
             * @return outFn The output function, taking an arbitrary calldata pointer
             *               and returning a dynamic array of Fulfillment types.
             */
            function _toFulfillmentsReturnType(
                function(CalldataPointer) internal pure returns (MemoryPointer) inFn
            )
                internal
                pure
                returns (
                    function(CalldataPointer)
                        internal
                        pure
                        returns (Fulfillment[] memory) outFn
                )
            {
                assembly {
                    outFn := inFn
                }
            }
            /**
             * @dev Caches the endAmount in an offer item and replaces it with
             * a given recipient so that its memory may be reused as a temporary
             * ReceivedItem.
             *
             * @param offerItem The offer item.
             * @param recipient The recipient.
             *
             * @return originalEndAmount The original end amount.
             */
            function _replaceEndAmountWithRecipient(
                OfferItem memory offerItem,
                address recipient
            ) internal pure returns (uint256 originalEndAmount) {
                assembly {
                    // Derive the pointer to the end amount on the offer item.
                    let endAmountPtr := add(offerItem, ReceivedItem_recipient_offset)
                    // Retrieve the value of the end amount on the offer item.
                    originalEndAmount := mload(endAmountPtr)
                    // Write recipient to received item at the offer end amount pointer.
                    mstore(endAmountPtr, recipient)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.13;
        /**
         * @title ReentrancyErrors
         * @author 0age
         * @notice ReentrancyErrors contains errors related to reentrancy.
         */
        interface ReentrancyErrors {
            /**
             * @dev Revert with an error when a caller attempts to reenter a protected
             *      function.
             */
            error NoReentrantCalls();
            /**
             * @dev Revert with an error when attempting to activate the TSTORE opcode
             *      when it is already active.
             */
            error TStoreAlreadyActivated();
            /**
             * @dev Revert with an error when attempting to activate the TSTORE opcode
             *      in an EVM environment that does not support it.
             */
            error TStoreNotSupported();
            /**
             * @dev Revert with an error when deployment of the contract for testing
             *      TSTORE support fails.
             */
            error TloadTestContractDeploymentFailed();
        }
        

        File 2 of 5: SPCHRON
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @title: SPCHRONICLES
        /// @author: manifold.xyz
        import "./manifold/ERC721Creator.sol";
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //                                                                                                                                     //
        //                                                                                                                                     //
        //     ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░      ░▒▓████████▓▒░░▒▓███████▓▒░     //
        //    ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░      ░▒▓█▓▒░      ░▒▓█▓▒░            //
        //    ░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░      ░▒▓█▓▒░      ░▒▓█▓▒░      ░▒▓█▓▒░            //
        //    ░▒▓█▓▒░      ░▒▓████████▓▒░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░      ░▒▓█▓▒░      ░▒▓██████▓▒░  ░▒▓██████▓▒░      //
        //    ░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░      ░▒▓█▓▒░      ░▒▓█▓▒░             ░▒▓█▓▒░     //
        //    ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░      ░▒▓█▓▒░             ░▒▓█▓▒░     //
        //     ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░▒▓███████▓▒░      //
        //                                                                                                                                     //
        //                                                                                                                                     //
        //                                                                                                                                     //
        //                                                                                                                                     //
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        contract SPCHRON is ERC721Creator {
            constructor() ERC721Creator("SPCHRONICLES", "SPCHRON") {}
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/proxy/Proxy.sol";
        import "@openzeppelin/contracts/utils/Address.sol";
        import "@openzeppelin/contracts/utils/StorageSlot.sol";
        contract ERC721Creator is Proxy {
            
            constructor(string memory name, string memory symbol) {
                assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = 0x5133522ea5A0494EcB83F26311A095DDD7a9D4b6;
                (bool success, ) = 0x5133522ea5A0494EcB83F26311A095DDD7a9D4b6.delegatecall(abi.encodeWithSignature("initialize(string,string)", name, symbol));
                require(success, "Initialization failed");
            }
                
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev Returns the current implementation address.
             */
             function implementation() public view returns (address) {
                return _implementation();
            }
            function _implementation() internal override view returns (address) {
                return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
            }    
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
         * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
         * be specified by overriding the virtual {_implementation} function.
         *
         * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
         * different contract through the {_delegate} function.
         *
         * The success and return data of the delegated call will be returned back to the caller of the proxy.
         */
        abstract contract Proxy {
            /**
             * @dev Delegates the current call to `implementation`.
             *
             * This function does not return to its internal call site, it will return directly to the external caller.
             */
            function _delegate(address implementation) internal virtual {
                assembly {
                    // Copy msg.data. We take full control of memory in this inline assembly
                    // block because it will not return to Solidity code. We overwrite the
                    // Solidity scratch pad at memory position 0.
                    calldatacopy(0, 0, calldatasize())
                    // Call the implementation.
                    // out and outsize are 0 because we don't know the size yet.
                    let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                    // Copy the returned data.
                    returndatacopy(0, 0, returndatasize())
                    switch result
                    // delegatecall returns 0 on error.
                    case 0 {
                        revert(0, returndatasize())
                    }
                    default {
                        return(0, returndatasize())
                    }
                }
            }
            /**
             * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
             * and {_fallback} should delegate.
             */
            function _implementation() internal view virtual returns (address);
            /**
             * @dev Delegates the current call to the address returned by `_implementation()`.
             *
             * This function does not return to its internal call site, it will return directly to the external caller.
             */
            function _fallback() internal virtual {
                _beforeFallback();
                _delegate(_implementation());
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
             * function in the contract matches the call data.
             */
            fallback() external payable virtual {
                _fallback();
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
             * is empty.
             */
            receive() external payable virtual {
                _fallback();
            }
            /**
             * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
             * call, or as part of the Solidity `fallback` or `receive` functions.
             *
             * If overridden should call `super._beforeFallback()`.
             */
            function _beforeFallback() internal virtual {}
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
        pragma solidity ^0.8.1;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
            /**
             * @dev Returns true if `account` is a contract.
             *
             * [IMPORTANT]
             * ====
             * It is unsafe to assume that an address for which this function returns
             * false is an externally-owned account (EOA) and not a contract.
             *
             * Among others, `isContract` will return false for the following
             * types of addresses:
             *
             *  - an externally-owned account
             *  - a contract in construction
             *  - an address where a contract will be created
             *  - an address where a contract lived, but was destroyed
             *
             * Furthermore, `isContract` will also return true if the target contract within
             * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
             * which only has an effect at the end of a transaction.
             * ====
             *
             * [IMPORTANT]
             * ====
             * You shouldn't rely on `isContract` to protect against flash loan attacks!
             *
             * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
             * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
             * constructor.
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize/address.code.length, which returns 0
                // for contracts in construction, since the code is only stored at the end
                // of the constructor execution.
                return account.code.length > 0;
            }
            /**
             * @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 isContract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        require(isContract(target), "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
        // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
        // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
        pragma solidity ^0.8.0;
        /**
         * @dev Library for reading and writing primitive types to specific storage slots.
         *
         * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
         * This library helps with reading and writing to such slots without the need for inline assembly.
         *
         * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
         *
         * Example usage to set ERC1967 implementation slot:
         * ```solidity
         * contract ERC1967 {
         *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
         *
         *     function _getImplementation() internal view returns (address) {
         *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
         *     }
         *
         *     function _setImplementation(address newImplementation) internal {
         *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
         *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
         *     }
         * }
         * ```
         *
         * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
         * _Available since v4.9 for `string`, `bytes`._
         */
        library StorageSlot {
            struct AddressSlot {
                address value;
            }
            struct BooleanSlot {
                bool value;
            }
            struct Bytes32Slot {
                bytes32 value;
            }
            struct Uint256Slot {
                uint256 value;
            }
            struct StringSlot {
                string value;
            }
            struct BytesSlot {
                bytes value;
            }
            /**
             * @dev Returns an `AddressSlot` with member `value` located at `slot`.
             */
            function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
             */
            function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
             */
            function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
             */
            function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `StringSlot` with member `value` located at `slot`.
             */
            function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
             */
            function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := store.slot
                }
            }
            /**
             * @dev Returns an `BytesSlot` with member `value` located at `slot`.
             */
            function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
             */
            function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := store.slot
                }
            }
        }
        

        File 3 of 5: Conduit
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
        import { ConduitItemType } from "./lib/ConduitEnums.sol";
        import { TokenTransferrer } from "../lib/TokenTransferrer.sol";
        // prettier-ignore
        import {
            ConduitTransfer,
            ConduitBatch1155Transfer
        } from "./lib/ConduitStructs.sol";
        import "./lib/ConduitConstants.sol";
        /**
         * @title Conduit
         * @author 0age
         * @notice This contract serves as an originator for "proxied" transfers. Each
         *         conduit is deployed and controlled by a "conduit controller" that can
         *         add and remove "channels" or contracts that can instruct the conduit
         *         to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each
         *         conduit has an owner that can arbitrarily add or remove channels, and
         *         a malicious or negligent owner can add a channel that allows for any
         *         approved ERC20/721/1155 tokens to be taken immediately — be extremely
         *         cautious with what conduits you give token approvals to!*
         */
        contract Conduit is ConduitInterface, TokenTransferrer {
            // Set deployer as an immutable controller that can update channel statuses.
            address private immutable _controller;
            // Track the status of each channel.
            mapping(address => bool) private _channels;
            /**
             * @notice Ensure that the caller is currently registered as an open channel
             *         on the conduit.
             */
            modifier onlyOpenChannel() {
                // Utilize assembly to access channel storage mapping directly.
                assembly {
                    // Write the caller to scratch space.
                    mstore(ChannelKey_channel_ptr, caller())
                    // Write the storage slot for _channels to scratch space.
                    mstore(ChannelKey_slot_ptr, _channels.slot)
                    // Derive the position in storage of _channels[msg.sender]
                    // and check if the stored value is zero.
                    if iszero(
                        sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))
                    ) {
                        // The caller is not an open channel; revert with
                        // ChannelClosed(caller). First, set error signature in memory.
                        mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature)
                        // Next, set the caller as the argument.
                        mstore(ChannelClosed_channel_ptr, caller())
                        // Finally, revert, returning full custom error with argument.
                        revert(ChannelClosed_error_ptr, ChannelClosed_error_length)
                    }
                }
                // Continue with function execution.
                _;
            }
            /**
             * @notice In the constructor, set the deployer as the controller.
             */
            constructor() {
                // Set the deployer as the controller.
                _controller = msg.sender;
            }
            /**
             * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
             *         with an open channel can call this function. Note that channels
             *         are expected to implement reentrancy protection if desired, and
             *         that cross-channel reentrancy may be possible if the conduit has
             *         multiple open channels at once. Also note that channels are
             *         expected to implement checks against transferring any zero-amount
             *         items if that constraint is desired.
             *
             * @param transfers The ERC20/721/1155 transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function execute(ConduitTransfer[] calldata transfers)
                external
                override
                onlyOpenChannel
                returns (bytes4 magicValue)
            {
                // Retrieve the total number of transfers and place on the stack.
                uint256 totalStandardTransfers = transfers.length;
                // Iterate over each transfer.
                for (uint256 i = 0; i < totalStandardTransfers; ) {
                    // Retrieve the transfer in question and perform the transfer.
                    _transfer(transfers[i]);
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        ++i;
                    }
                }
                // Return a magic value indicating that the transfers were performed.
                magicValue = this.execute.selector;
            }
            /**
             * @notice Execute a sequence of batch 1155 item transfers. Only a caller
             *         with an open channel can call this function. Note that channels
             *         are expected to implement reentrancy protection if desired, and
             *         that cross-channel reentrancy may be possible if the conduit has
             *         multiple open channels at once. Also note that channels are
             *         expected to implement checks against transferring any zero-amount
             *         items if that constraint is desired.
             *
             * @param batchTransfers The 1155 batch item transfers to perform.
             *
             * @return magicValue A magic value indicating that the item transfers were
             *                    performed successfully.
             */
            function executeBatch1155(
                ConduitBatch1155Transfer[] calldata batchTransfers
            ) external override onlyOpenChannel returns (bytes4 magicValue) {
                // Perform 1155 batch transfers. Note that memory should be considered
                // entirely corrupted from this point forward.
                _performERC1155BatchTransfers(batchTransfers);
                // Return a magic value indicating that the transfers were performed.
                magicValue = this.executeBatch1155.selector;
            }
            /**
             * @notice Execute a sequence of transfers, both single ERC20/721/1155 item
             *         transfers as well as batch 1155 item transfers. Only a caller
             *         with an open channel can call this function. Note that channels
             *         are expected to implement reentrancy protection if desired, and
             *         that cross-channel reentrancy may be possible if the conduit has
             *         multiple open channels at once. Also note that channels are
             *         expected to implement checks against transferring any zero-amount
             *         items if that constraint is desired.
             *
             * @param standardTransfers The ERC20/721/1155 item transfers to perform.
             * @param batchTransfers    The 1155 batch item transfers to perform.
             *
             * @return magicValue A magic value indicating that the item transfers were
             *                    performed successfully.
             */
            function executeWithBatch1155(
                ConduitTransfer[] calldata standardTransfers,
                ConduitBatch1155Transfer[] calldata batchTransfers
            ) external override onlyOpenChannel returns (bytes4 magicValue) {
                // Retrieve the total number of transfers and place on the stack.
                uint256 totalStandardTransfers = standardTransfers.length;
                // Iterate over each standard transfer.
                for (uint256 i = 0; i < totalStandardTransfers; ) {
                    // Retrieve the transfer in question and perform the transfer.
                    _transfer(standardTransfers[i]);
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        ++i;
                    }
                }
                // Perform 1155 batch transfers. Note that memory should be considered
                // entirely corrupted from this point forward aside from the free memory
                // pointer having the default value.
                _performERC1155BatchTransfers(batchTransfers);
                // Return a magic value indicating that the transfers were performed.
                magicValue = this.executeWithBatch1155.selector;
            }
            /**
             * @notice Open or close a given channel. Only callable by the controller.
             *
             * @param channel The channel to open or close.
             * @param isOpen  The status of the channel (either open or closed).
             */
            function updateChannel(address channel, bool isOpen) external override {
                // Ensure that the caller is the controller of this contract.
                if (msg.sender != _controller) {
                    revert InvalidController();
                }
                // Ensure that the channel does not already have the indicated status.
                if (_channels[channel] == isOpen) {
                    revert ChannelStatusAlreadySet(channel, isOpen);
                }
                // Update the status of the channel.
                _channels[channel] = isOpen;
                // Emit a corresponding event.
                emit ChannelUpdated(channel, isOpen);
            }
            /**
             * @dev Internal function to transfer a given ERC20/721/1155 item. Note that
             *      channels are expected to implement checks against transferring any
             *      zero-amount items if that constraint is desired.
             *
             * @param item The ERC20/721/1155 item to transfer.
             */
            function _transfer(ConduitTransfer calldata item) internal {
                // Determine the transfer method based on the respective item type.
                if (item.itemType == ConduitItemType.ERC20) {
                    // Transfer ERC20 token. Note that item.identifier is ignored and
                    // therefore ERC20 transfer items are potentially malleable — this
                    // check should be performed by the calling channel if a constraint
                    // on item malleability is desired.
                    _performERC20Transfer(item.token, item.from, item.to, item.amount);
                } else if (item.itemType == ConduitItemType.ERC721) {
                    // Ensure that exactly one 721 item is being transferred.
                    if (item.amount != 1) {
                        revert InvalidERC721TransferAmount();
                    }
                    // Transfer ERC721 token.
                    _performERC721Transfer(
                        item.token,
                        item.from,
                        item.to,
                        item.identifier
                    );
                } else if (item.itemType == ConduitItemType.ERC1155) {
                    // Transfer ERC1155 token.
                    _performERC1155Transfer(
                        item.token,
                        item.from,
                        item.to,
                        item.identifier,
                        item.amount
                    );
                } else {
                    // Throw with an error.
                    revert InvalidItemType();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        // prettier-ignore
        import {
            ConduitTransfer,
            ConduitBatch1155Transfer
        } from "../conduit/lib/ConduitStructs.sol";
        /**
         * @title ConduitInterface
         * @author 0age
         * @notice ConduitInterface contains all external function interfaces, events,
         *         and errors for conduit contracts.
         */
        interface ConduitInterface {
            /**
             * @dev Revert with an error when attempting to execute transfers using a
             *      caller that does not have an open channel.
             */
            error ChannelClosed(address channel);
            /**
             * @dev Revert with an error when attempting to update a channel to the
             *      current status of that channel.
             */
            error ChannelStatusAlreadySet(address channel, bool isOpen);
            /**
             * @dev Revert with an error when attempting to execute a transfer for an
             *      item that does not have an ERC20/721/1155 item type.
             */
            error InvalidItemType();
            /**
             * @dev Revert with an error when attempting to update the status of a
             *      channel from a caller that is not the conduit controller.
             */
            error InvalidController();
            /**
             * @dev Emit an event whenever a channel is opened or closed.
             *
             * @param channel The channel that has been updated.
             * @param open    A boolean indicating whether the conduit is open or not.
             */
            event ChannelUpdated(address indexed channel, bool open);
            /**
             * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
             *         with an open channel can call this function.
             *
             * @param transfers The ERC20/721/1155 transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function execute(ConduitTransfer[] calldata transfers)
                external
                returns (bytes4 magicValue);
            /**
             * @notice Execute a sequence of batch 1155 transfers. Only a caller with an
             *         open channel can call this function.
             *
             * @param batch1155Transfers The 1155 batch transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function executeBatch1155(
                ConduitBatch1155Transfer[] calldata batch1155Transfers
            ) external returns (bytes4 magicValue);
            /**
             * @notice Execute a sequence of transfers, both single and batch 1155. Only
             *         a caller with an open channel can call this function.
             *
             * @param standardTransfers  The ERC20/721/1155 transfers to perform.
             * @param batch1155Transfers The 1155 batch transfers to perform.
             *
             * @return magicValue A magic value indicating that the transfers were
             *                    performed successfully.
             */
            function executeWithBatch1155(
                ConduitTransfer[] calldata standardTransfers,
                ConduitBatch1155Transfer[] calldata batch1155Transfers
            ) external returns (bytes4 magicValue);
            /**
             * @notice Open or close a given channel. Only callable by the controller.
             *
             * @param channel The channel to open or close.
             * @param isOpen  The status of the channel (either open or closed).
             */
            function updateChannel(address channel, bool isOpen) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        enum ConduitItemType {
            NATIVE, // unused
            ERC20,
            ERC721,
            ERC1155
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        import "./TokenTransferrerConstants.sol";
        // prettier-ignore
        import {
            TokenTransferrerErrors
        } from "../interfaces/TokenTransferrerErrors.sol";
        import { ConduitBatch1155Transfer } from "../conduit/lib/ConduitStructs.sol";
        /**
         * @title TokenTransferrer
         * @author 0age
         * @custom:coauthor d1ll0n
         * @custom:coauthor transmissions11
         * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,
         *         ERC1155, and batch ERC1155 transfers, used by both Seaport as well as
         *         by conduits deployed by the ConduitController. Use great caution when
         *         considering these functions for use in other codebases, as there are
         *         significant side effects and edge cases that need to be thoroughly
         *         understood and carefully addressed.
         */
        contract TokenTransferrer is TokenTransferrerErrors {
            /**
             * @dev Internal function to transfer ERC20 tokens from a given originator
             *      to a given recipient. Sufficient approvals must be set on the
             *      contract performing the transfer.
             *
             * @param token      The ERC20 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param amount     The amount to transfer.
             */
            function _performERC20Transfer(
                address token,
                address from,
                address to,
                uint256 amount
            ) internal {
                // Utilize assembly to perform an optimized ERC20 token transfer.
                assembly {
                    // The free memory pointer memory slot will be used when populating
                    // call data for the transfer; read the value and restore it later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    // Write call data into memory, starting with function selector.
                    mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)
                    mstore(ERC20_transferFrom_from_ptr, from)
                    mstore(ERC20_transferFrom_to_ptr, to)
                    mstore(ERC20_transferFrom_amount_ptr, amount)
                    // Make call & copy up to 32 bytes of return data to scratch space.
                    // Scratch space does not need to be cleared ahead of time, as the
                    // subsequent check will ensure that either at least a full word of
                    // return data is received (in which case it will be overwritten) or
                    // that no data is received (in which case scratch space will be
                    // ignored) on a successful call to the given token.
                    let callStatus := call(
                        gas(),
                        token,
                        0,
                        ERC20_transferFrom_sig_ptr,
                        ERC20_transferFrom_length,
                        0,
                        OneWord
                    )
                    // Determine whether transfer was successful using status & result.
                    let success := and(
                        // Set success to whether the call reverted, if not check it
                        // either returned exactly 1 (can't just be non-zero data), or
                        // had no return data.
                        or(
                            and(eq(mload(0), 1), gt(returndatasize(), 31)),
                            iszero(returndatasize())
                        ),
                        callStatus
                    )
                    // Handle cases where either the transfer failed or no data was
                    // returned. Group these, as most transfers will succeed with data.
                    // Equivalent to `or(iszero(success), iszero(returndatasize()))`
                    // but after it's inverted for JUMPI this expression is cheaper.
                    if iszero(and(success, iszero(iszero(returndatasize())))) {
                        // If the token has no code or the transfer failed: Equivalent
                        // to `or(iszero(success), iszero(extcodesize(token)))` but
                        // after it's inverted for JUMPI this expression is cheaper.
                        if iszero(and(iszero(iszero(extcodesize(token))), success)) {
                            // If the transfer failed:
                            if iszero(success) {
                                // If it was due to a revert:
                                if iszero(callStatus) {
                                    // If it returned a message, bubble it up as long as
                                    // sufficient gas remains to do so:
                                    if returndatasize() {
                                        // Ensure that sufficient gas is available to
                                        // copy returndata while expanding memory where
                                        // necessary. Start by computing the word size
                                        // of returndata and allocated memory. Round up
                                        // to the nearest full word.
                                        let returnDataWords := div(
                                            add(returndatasize(), AlmostOneWord),
                                            OneWord
                                        )
                                        // Note: use the free memory pointer in place of
                                        // msize() to work around a Yul warning that
                                        // prevents accessing msize directly when the IR
                                        // pipeline is activated.
                                        let msizeWords := div(memPointer, OneWord)
                                        // Next, compute the cost of the returndatacopy.
                                        let cost := mul(CostPerWord, returnDataWords)
                                        // Then, compute cost of new memory allocation.
                                        if gt(returnDataWords, msizeWords) {
                                            cost := add(
                                                cost,
                                                add(
                                                    mul(
                                                        sub(
                                                            returnDataWords,
                                                            msizeWords
                                                        ),
                                                        CostPerWord
                                                    ),
                                                    div(
                                                        sub(
                                                            mul(
                                                                returnDataWords,
                                                                returnDataWords
                                                            ),
                                                            mul(msizeWords, msizeWords)
                                                        ),
                                                        MemoryExpansionCoefficient
                                                    )
                                                )
                                            )
                                        }
                                        // Finally, add a small constant and compare to
                                        // gas remaining; bubble up the revert data if
                                        // enough gas is still available.
                                        if lt(add(cost, ExtraGasBuffer), gas()) {
                                            // Copy returndata to memory; overwrite
                                            // existing memory.
                                            returndatacopy(0, 0, returndatasize())
                                            // Revert, specifying memory region with
                                            // copied returndata.
                                            revert(0, returndatasize())
                                        }
                                    }
                                    // Otherwise revert with a generic error message.
                                    mstore(
                                        TokenTransferGenericFailure_error_sig_ptr,
                                        TokenTransferGenericFailure_error_signature
                                    )
                                    mstore(
                                        TokenTransferGenericFailure_error_token_ptr,
                                        token
                                    )
                                    mstore(
                                        TokenTransferGenericFailure_error_from_ptr,
                                        from
                                    )
                                    mstore(TokenTransferGenericFailure_error_to_ptr, to)
                                    mstore(TokenTransferGenericFailure_error_id_ptr, 0)
                                    mstore(
                                        TokenTransferGenericFailure_error_amount_ptr,
                                        amount
                                    )
                                    revert(
                                        TokenTransferGenericFailure_error_sig_ptr,
                                        TokenTransferGenericFailure_error_length
                                    )
                                }
                                // Otherwise revert with a message about the token
                                // returning false or non-compliant return values.
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_sig_ptr,
                                    BadReturnValueFromERC20OnTransfer_error_signature
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_token_ptr,
                                    token
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_from_ptr,
                                    from
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_to_ptr,
                                    to
                                )
                                mstore(
                                    BadReturnValueFromERC20OnTransfer_error_amount_ptr,
                                    amount
                                )
                                revert(
                                    BadReturnValueFromERC20OnTransfer_error_sig_ptr,
                                    BadReturnValueFromERC20OnTransfer_error_length
                                )
                            }
                            // Otherwise, revert with error about token not having code:
                            mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                            mstore(NoContract_error_token_ptr, token)
                            revert(NoContract_error_sig_ptr, NoContract_error_length)
                        }
                        // Otherwise, the token just returned no data despite the call
                        // having succeeded; no need to optimize for this as it's not
                        // technically ERC20 compliant.
                    }
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer an ERC721 token from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer. Note that this function does
             *      not check whether the receiver can accept the ERC721 token (i.e. it
             *      does not use `safeTransferFrom`).
             *
             * @param token      The ERC721 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param identifier The tokenId to transfer.
             */
            function _performERC721Transfer(
                address token,
                address from,
                address to,
                uint256 identifier
            ) internal {
                // Utilize assembly to perform an optimized ERC721 token transfer.
                assembly {
                    // If the token has no code, revert.
                    if iszero(extcodesize(token)) {
                        mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                        mstore(NoContract_error_token_ptr, token)
                        revert(NoContract_error_sig_ptr, NoContract_error_length)
                    }
                    // The free memory pointer memory slot will be used when populating
                    // call data for the transfer; read the value and restore it later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    // Write call data to memory starting with function selector.
                    mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)
                    mstore(ERC721_transferFrom_from_ptr, from)
                    mstore(ERC721_transferFrom_to_ptr, to)
                    mstore(ERC721_transferFrom_id_ptr, identifier)
                    // Perform the call, ignoring return data.
                    let success := call(
                        gas(),
                        token,
                        0,
                        ERC721_transferFrom_sig_ptr,
                        ERC721_transferFrom_length,
                        0,
                        0
                    )
                    // If the transfer reverted:
                    if iszero(success) {
                        // If it returned a message, bubble it up as long as sufficient
                        // gas remains to do so:
                        if returndatasize() {
                            // Ensure that sufficient gas is available to copy
                            // returndata while expanding memory where necessary. Start
                            // by computing word size of returndata & allocated memory.
                            // Round up to the nearest full word.
                            let returnDataWords := div(
                                add(returndatasize(), AlmostOneWord),
                                OneWord
                            )
                            // Note: use the free memory pointer in place of msize() to
                            // work around a Yul warning that prevents accessing msize
                            // directly when the IR pipeline is activated.
                            let msizeWords := div(memPointer, OneWord)
                            // Next, compute the cost of the returndatacopy.
                            let cost := mul(CostPerWord, returnDataWords)
                            // Then, compute cost of new memory allocation.
                            if gt(returnDataWords, msizeWords) {
                                cost := add(
                                    cost,
                                    add(
                                        mul(
                                            sub(returnDataWords, msizeWords),
                                            CostPerWord
                                        ),
                                        div(
                                            sub(
                                                mul(returnDataWords, returnDataWords),
                                                mul(msizeWords, msizeWords)
                                            ),
                                            MemoryExpansionCoefficient
                                        )
                                    )
                                )
                            }
                            // Finally, add a small constant and compare to gas
                            // remaining; bubble up the revert data if enough gas is
                            // still available.
                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                // Copy returndata to memory; overwrite existing memory.
                                returndatacopy(0, 0, returndatasize())
                                // Revert, giving memory region with copied returndata.
                                revert(0, returndatasize())
                            }
                        }
                        // Otherwise revert with a generic error message.
                        mstore(
                            TokenTransferGenericFailure_error_sig_ptr,
                            TokenTransferGenericFailure_error_signature
                        )
                        mstore(TokenTransferGenericFailure_error_token_ptr, token)
                        mstore(TokenTransferGenericFailure_error_from_ptr, from)
                        mstore(TokenTransferGenericFailure_error_to_ptr, to)
                        mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
                        mstore(TokenTransferGenericFailure_error_amount_ptr, 1)
                        revert(
                            TokenTransferGenericFailure_error_sig_ptr,
                            TokenTransferGenericFailure_error_length
                        )
                    }
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer ERC1155 tokens from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer and contract recipients must
             *      implement the ERC1155TokenReceiver interface to indicate that they
             *      are willing to accept the transfer.
             *
             * @param token      The ERC1155 token to transfer.
             * @param from       The originator of the transfer.
             * @param to         The recipient of the transfer.
             * @param identifier The id to transfer.
             * @param amount     The amount to transfer.
             */
            function _performERC1155Transfer(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount
            ) internal {
                // Utilize assembly to perform an optimized ERC1155 token transfer.
                assembly {
                    // If the token has no code, revert.
                    if iszero(extcodesize(token)) {
                        mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                        mstore(NoContract_error_token_ptr, token)
                        revert(NoContract_error_sig_ptr, NoContract_error_length)
                    }
                    // The following memory slots will be used when populating call data
                    // for the transfer; read the values and restore them later.
                    let memPointer := mload(FreeMemoryPointerSlot)
                    let slot0x80 := mload(Slot0x80)
                    let slot0xA0 := mload(Slot0xA0)
                    let slot0xC0 := mload(Slot0xC0)
                    // Write call data into memory, beginning with function selector.
                    mstore(
                        ERC1155_safeTransferFrom_sig_ptr,
                        ERC1155_safeTransferFrom_signature
                    )
                    mstore(ERC1155_safeTransferFrom_from_ptr, from)
                    mstore(ERC1155_safeTransferFrom_to_ptr, to)
                    mstore(ERC1155_safeTransferFrom_id_ptr, identifier)
                    mstore(ERC1155_safeTransferFrom_amount_ptr, amount)
                    mstore(
                        ERC1155_safeTransferFrom_data_offset_ptr,
                        ERC1155_safeTransferFrom_data_length_offset
                    )
                    mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)
                    // Perform the call, ignoring return data.
                    let success := call(
                        gas(),
                        token,
                        0,
                        ERC1155_safeTransferFrom_sig_ptr,
                        ERC1155_safeTransferFrom_length,
                        0,
                        0
                    )
                    // If the transfer reverted:
                    if iszero(success) {
                        // If it returned a message, bubble it up as long as sufficient
                        // gas remains to do so:
                        if returndatasize() {
                            // Ensure that sufficient gas is available to copy
                            // returndata while expanding memory where necessary. Start
                            // by computing word size of returndata & allocated memory.
                            // Round up to the nearest full word.
                            let returnDataWords := div(
                                add(returndatasize(), AlmostOneWord),
                                OneWord
                            )
                            // Note: use the free memory pointer in place of msize() to
                            // work around a Yul warning that prevents accessing msize
                            // directly when the IR pipeline is activated.
                            let msizeWords := div(memPointer, OneWord)
                            // Next, compute the cost of the returndatacopy.
                            let cost := mul(CostPerWord, returnDataWords)
                            // Then, compute cost of new memory allocation.
                            if gt(returnDataWords, msizeWords) {
                                cost := add(
                                    cost,
                                    add(
                                        mul(
                                            sub(returnDataWords, msizeWords),
                                            CostPerWord
                                        ),
                                        div(
                                            sub(
                                                mul(returnDataWords, returnDataWords),
                                                mul(msizeWords, msizeWords)
                                            ),
                                            MemoryExpansionCoefficient
                                        )
                                    )
                                )
                            }
                            // Finally, add a small constant and compare to gas
                            // remaining; bubble up the revert data if enough gas is
                            // still available.
                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                // Copy returndata to memory; overwrite existing memory.
                                returndatacopy(0, 0, returndatasize())
                                // Revert, giving memory region with copied returndata.
                                revert(0, returndatasize())
                            }
                        }
                        // Otherwise revert with a generic error message.
                        mstore(
                            TokenTransferGenericFailure_error_sig_ptr,
                            TokenTransferGenericFailure_error_signature
                        )
                        mstore(TokenTransferGenericFailure_error_token_ptr, token)
                        mstore(TokenTransferGenericFailure_error_from_ptr, from)
                        mstore(TokenTransferGenericFailure_error_to_ptr, to)
                        mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
                        mstore(TokenTransferGenericFailure_error_amount_ptr, amount)
                        revert(
                            TokenTransferGenericFailure_error_sig_ptr,
                            TokenTransferGenericFailure_error_length
                        )
                    }
                    mstore(Slot0x80, slot0x80) // Restore slot 0x80.
                    mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.
                    mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.
                    // Restore the original free memory pointer.
                    mstore(FreeMemoryPointerSlot, memPointer)
                    // Restore the zero slot to zero.
                    mstore(ZeroSlot, 0)
                }
            }
            /**
             * @dev Internal function to transfer ERC1155 tokens from a given
             *      originator to a given recipient. Sufficient approvals must be set on
             *      the contract performing the transfer and contract recipients must
             *      implement the ERC1155TokenReceiver interface to indicate that they
             *      are willing to accept the transfer. NOTE: this function is not
             *      memory-safe; it will overwrite existing memory, restore the free
             *      memory pointer to the default value, and overwrite the zero slot.
             *      This function should only be called once memory is no longer
             *      required and when uninitialized arrays are not utilized, and memory
             *      should be considered fully corrupted (aside from the existence of a
             *      default-value free memory pointer) after calling this function.
             *
             * @param batchTransfers The group of 1155 batch transfers to perform.
             */
            function _performERC1155BatchTransfers(
                ConduitBatch1155Transfer[] calldata batchTransfers
            ) internal {
                // Utilize assembly to perform optimized batch 1155 transfers.
                assembly {
                    let len := batchTransfers.length
                    // Pointer to first head in the array, which is offset to the struct
                    // at each index. This gets incremented after each loop to avoid
                    // multiplying by 32 to get the offset for each element.
                    let nextElementHeadPtr := batchTransfers.offset
                    // Pointer to beginning of the head of the array. This is the
                    // reference position each offset references. It's held static to
                    // let each loop calculate the data position for an element.
                    let arrayHeadPtr := nextElementHeadPtr
                    // Write the function selector, which will be reused for each call:
                    // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)
                    mstore(
                        ConduitBatch1155Transfer_from_offset,
                        ERC1155_safeBatchTransferFrom_signature
                    )
                    // Iterate over each batch transfer.
                    for {
                        let i := 0
                    } lt(i, len) {
                        i := add(i, 1)
                    } {
                        // Read the offset to the beginning of the element and add
                        // it to pointer to the beginning of the array head to get
                        // the absolute position of the element in calldata.
                        let elementPtr := add(
                            arrayHeadPtr,
                            calldataload(nextElementHeadPtr)
                        )
                        // Retrieve the token from calldata.
                        let token := calldataload(elementPtr)
                        // If the token has no code, revert.
                        if iszero(extcodesize(token)) {
                            mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                            mstore(NoContract_error_token_ptr, token)
                            revert(NoContract_error_sig_ptr, NoContract_error_length)
                        }
                        // Get the total number of supplied ids.
                        let idsLength := calldataload(
                            add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)
                        )
                        // Determine the expected offset for the amounts array.
                        let expectedAmountsOffset := add(
                            ConduitBatch1155Transfer_amounts_length_baseOffset,
                            mul(idsLength, OneWord)
                        )
                        // Validate struct encoding.
                        let invalidEncoding := iszero(
                            and(
                                // ids.length == amounts.length
                                eq(
                                    idsLength,
                                    calldataload(add(elementPtr, expectedAmountsOffset))
                                ),
                                and(
                                    // ids_offset == 0xa0
                                    eq(
                                        calldataload(
                                            add(
                                                elementPtr,
                                                ConduitBatch1155Transfer_ids_head_offset
                                            )
                                        ),
                                        ConduitBatch1155Transfer_ids_length_offset
                                    ),
                                    // amounts_offset == 0xc0 + ids.length*32
                                    eq(
                                        calldataload(
                                            add(
                                                elementPtr,
                                                ConduitBatchTransfer_amounts_head_offset
                                            )
                                        ),
                                        expectedAmountsOffset
                                    )
                                )
                            )
                        )
                        // Revert with an error if the encoding is not valid.
                        if invalidEncoding {
                            mstore(
                                Invalid1155BatchTransferEncoding_ptr,
                                Invalid1155BatchTransferEncoding_selector
                            )
                            revert(
                                Invalid1155BatchTransferEncoding_ptr,
                                Invalid1155BatchTransferEncoding_length
                            )
                        }
                        // Update the offset position for the next loop
                        nextElementHeadPtr := add(nextElementHeadPtr, OneWord)
                        // Copy the first section of calldata (before dynamic values).
                        calldatacopy(
                            BatchTransfer1155Params_ptr,
                            add(elementPtr, ConduitBatch1155Transfer_from_offset),
                            ConduitBatch1155Transfer_usable_head_size
                        )
                        // Determine size of calldata required for ids and amounts. Note
                        // that the size includes both lengths as well as the data.
                        let idsAndAmountsSize := add(TwoWords, mul(idsLength, TwoWords))
                        // Update the offset for the data array in memory.
                        mstore(
                            BatchTransfer1155Params_data_head_ptr,
                            add(
                                BatchTransfer1155Params_ids_length_offset,
                                idsAndAmountsSize
                            )
                        )
                        // Set the length of the data array in memory to zero.
                        mstore(
                            add(
                                BatchTransfer1155Params_data_length_basePtr,
                                idsAndAmountsSize
                            ),
                            0
                        )
                        // Determine the total calldata size for the call to transfer.
                        let transferDataSize := add(
                            BatchTransfer1155Params_calldata_baseSize,
                            idsAndAmountsSize
                        )
                        // Copy second section of calldata (including dynamic values).
                        calldatacopy(
                            BatchTransfer1155Params_ids_length_ptr,
                            add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),
                            idsAndAmountsSize
                        )
                        // Perform the call to transfer 1155 tokens.
                        let success := call(
                            gas(),
                            token,
                            0,
                            ConduitBatch1155Transfer_from_offset, // Data portion start.
                            transferDataSize, // Location of the length of callData.
                            0,
                            0
                        )
                        // If the transfer reverted:
                        if iszero(success) {
                            // If it returned a message, bubble it up as long as
                            // sufficient gas remains to do so:
                            if returndatasize() {
                                // Ensure that sufficient gas is available to copy
                                // returndata while expanding memory where necessary.
                                // Start by computing word size of returndata and
                                // allocated memory. Round up to the nearest full word.
                                let returnDataWords := div(
                                    add(returndatasize(), AlmostOneWord),
                                    OneWord
                                )
                                // Note: use transferDataSize in place of msize() to
                                // work around a Yul warning that prevents accessing
                                // msize directly when the IR pipeline is activated.
                                // The free memory pointer is not used here because
                                // this function does almost all memory management
                                // manually and does not update it, and transferDataSize
                                // should be the largest memory value used (unless a
                                // previous batch was larger).
                                let msizeWords := div(transferDataSize, OneWord)
                                // Next, compute the cost of the returndatacopy.
                                let cost := mul(CostPerWord, returnDataWords)
                                // Then, compute cost of new memory allocation.
                                if gt(returnDataWords, msizeWords) {
                                    cost := add(
                                        cost,
                                        add(
                                            mul(
                                                sub(returnDataWords, msizeWords),
                                                CostPerWord
                                            ),
                                            div(
                                                sub(
                                                    mul(
                                                        returnDataWords,
                                                        returnDataWords
                                                    ),
                                                    mul(msizeWords, msizeWords)
                                                ),
                                                MemoryExpansionCoefficient
                                            )
                                        )
                                    )
                                }
                                // Finally, add a small constant and compare to gas
                                // remaining; bubble up the revert data if enough gas is
                                // still available.
                                if lt(add(cost, ExtraGasBuffer), gas()) {
                                    // Copy returndata to memory; overwrite existing.
                                    returndatacopy(0, 0, returndatasize())
                                    // Revert with memory region containing returndata.
                                    revert(0, returndatasize())
                                }
                            }
                            // Set the error signature.
                            mstore(
                                0,
                                ERC1155BatchTransferGenericFailure_error_signature
                            )
                            // Write the token.
                            mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)
                            // Increase the offset to ids by 32.
                            mstore(
                                BatchTransfer1155Params_ids_head_ptr,
                                ERC1155BatchTransferGenericFailure_ids_offset
                            )
                            // Increase the offset to amounts by 32.
                            mstore(
                                BatchTransfer1155Params_amounts_head_ptr,
                                add(
                                    OneWord,
                                    mload(BatchTransfer1155Params_amounts_head_ptr)
                                )
                            )
                            // Return modified region. The total size stays the same as
                            // `token` uses the same number of bytes as `data.length`.
                            revert(0, transferDataSize)
                        }
                    }
                    // Reset the free memory pointer to the default value; memory must
                    // be assumed to be dirtied and not reused from this point forward.
                    // Also note that the zero slot is not reset to zero, meaning empty
                    // arrays cannot be safely created or utilized until it is restored.
                    mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        import { ConduitItemType } from "./ConduitEnums.sol";
        struct ConduitTransfer {
            ConduitItemType itemType;
            address token;
            address from;
            address to;
            uint256 identifier;
            uint256 amount;
        }
        struct ConduitBatch1155Transfer {
            address token;
            address from;
            address to;
            uint256[] ids;
            uint256[] amounts;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        // error ChannelClosed(address channel)
        uint256 constant ChannelClosed_error_signature = (
            0x93daadf200000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ChannelClosed_error_ptr = 0x00;
        uint256 constant ChannelClosed_channel_ptr = 0x4;
        uint256 constant ChannelClosed_error_length = 0x24;
        // For the mapping:
        // mapping(address => bool) channels
        // The position in storage for a particular account is:
        // keccak256(abi.encode(account, channels.slot))
        uint256 constant ChannelKey_channel_ptr = 0x00;
        uint256 constant ChannelKey_slot_ptr = 0x20;
        uint256 constant ChannelKey_length = 0x40;
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        /*
         * -------------------------- Disambiguation & Other Notes ---------------------
         *    - The term "head" is used as it is in the documentation for ABI encoding,
         *      but only in reference to dynamic types, i.e. it always refers to the
         *      offset or pointer to the body of a dynamic type. In calldata, the head
         *      is always an offset (relative to the parent object), while in memory,
         *      the head is always the pointer to the body. More information found here:
         *      https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding
         *        - Note that the length of an array is separate from and precedes the
         *          head of the array.
         *
         *    - The term "body" is used in place of the term "head" used in the ABI
         *      documentation. It refers to the start of the data for a dynamic type,
         *      e.g. the first word of a struct or the first word of the first element
         *      in an array.
         *
         *    - The term "pointer" is used to describe the absolute position of a value
         *      and never an offset relative to another value.
         *        - The suffix "_ptr" refers to a memory pointer.
         *        - The suffix "_cdPtr" refers to a calldata pointer.
         *
         *    - The term "offset" is used to describe the position of a value relative
         *      to some parent value. For example, OrderParameters_conduit_offset is the
         *      offset to the "conduit" value in the OrderParameters struct relative to
         *      the start of the body.
         *        - Note: Offsets are used to derive pointers.
         *
         *    - Some structs have pointers defined for all of their fields in this file.
         *      Lines which are commented out are fields that are not used in the
         *      codebase but have been left in for readability.
         */
        uint256 constant AlmostOneWord = 0x1f;
        uint256 constant OneWord = 0x20;
        uint256 constant TwoWords = 0x40;
        uint256 constant ThreeWords = 0x60;
        uint256 constant FreeMemoryPointerSlot = 0x40;
        uint256 constant ZeroSlot = 0x60;
        uint256 constant DefaultFreeMemoryPointer = 0x80;
        uint256 constant Slot0x80 = 0x80;
        uint256 constant Slot0xA0 = 0xa0;
        uint256 constant Slot0xC0 = 0xc0;
        // abi.encodeWithSignature("transferFrom(address,address,uint256)")
        uint256 constant ERC20_transferFrom_signature = (
            0x23b872dd00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC20_transferFrom_sig_ptr = 0x0;
        uint256 constant ERC20_transferFrom_from_ptr = 0x04;
        uint256 constant ERC20_transferFrom_to_ptr = 0x24;
        uint256 constant ERC20_transferFrom_amount_ptr = 0x44;
        uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
        // abi.encodeWithSignature(
        //     "safeTransferFrom(address,address,uint256,uint256,bytes)"
        // )
        uint256 constant ERC1155_safeTransferFrom_signature = (
            0xf242432a00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;
        uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;
        uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;
        uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;
        uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;
        uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;
        uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;
        uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196
        uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;
        // abi.encodeWithSignature(
        //     "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
        // )
        uint256 constant ERC1155_safeBatchTransferFrom_signature = (
            0x2eb2c2d600000000000000000000000000000000000000000000000000000000
        );
        bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(
            bytes32(ERC1155_safeBatchTransferFrom_signature)
        );
        uint256 constant ERC721_transferFrom_signature = ERC20_transferFrom_signature;
        uint256 constant ERC721_transferFrom_sig_ptr = 0x0;
        uint256 constant ERC721_transferFrom_from_ptr = 0x04;
        uint256 constant ERC721_transferFrom_to_ptr = 0x24;
        uint256 constant ERC721_transferFrom_id_ptr = 0x44;
        uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
        // abi.encodeWithSignature("NoContract(address)")
        uint256 constant NoContract_error_signature = (
            0x5f15d67200000000000000000000000000000000000000000000000000000000
        );
        uint256 constant NoContract_error_sig_ptr = 0x0;
        uint256 constant NoContract_error_token_ptr = 0x4;
        uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36
        // abi.encodeWithSignature(
        //     "TokenTransferGenericFailure(address,address,address,uint256,uint256)"
        // )
        uint256 constant TokenTransferGenericFailure_error_signature = (
            0xf486bc8700000000000000000000000000000000000000000000000000000000
        );
        uint256 constant TokenTransferGenericFailure_error_sig_ptr = 0x0;
        uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x4;
        uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x24;
        uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x44;
        uint256 constant TokenTransferGenericFailure_error_id_ptr = 0x64;
        uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0x84;
        // 4 + 32 * 5 == 164
        uint256 constant TokenTransferGenericFailure_error_length = 0xa4;
        // abi.encodeWithSignature(
        //     "BadReturnValueFromERC20OnTransfer(address,address,address,uint256)"
        // )
        uint256 constant BadReturnValueFromERC20OnTransfer_error_signature = (
            0x9889192300000000000000000000000000000000000000000000000000000000
        );
        uint256 constant BadReturnValueFromERC20OnTransfer_error_sig_ptr = 0x0;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x4;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x24;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x44;
        uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x64;
        // 4 + 32 * 4 == 132
        uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
        uint256 constant ExtraGasBuffer = 0x20;
        uint256 constant CostPerWord = 3;
        uint256 constant MemoryExpansionCoefficient = 0x200;
        // Values are offset by 32 bytes in order to write the token to the beginning
        // in the event of a revert
        uint256 constant BatchTransfer1155Params_ptr = 0x24;
        uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;
        uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;
        uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;
        uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;
        uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;
        uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;
        uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;
        uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;
        uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;
        uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;
        uint256 constant ConduitBatch1155Transfer_from_offset = 0x20;
        uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;
        uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;
        uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;
        uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;
        uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;
        // Note: abbreviated version of above constant to adhere to line length limit.
        uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;
        uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;
        uint256 constant Invalid1155BatchTransferEncoding_length = 0x04;
        uint256 constant Invalid1155BatchTransferEncoding_selector = (
            0xeba2084c00000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155BatchTransferGenericFailure_error_signature = (
            0xafc445e200000000000000000000000000000000000000000000000000000000
        );
        uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;
        uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.8.7;
        /**
         * @title TokenTransferrerErrors
         */
        interface TokenTransferrerErrors {
            /**
             * @dev Revert with an error when an ERC721 transfer with amount other than
             *      one is attempted.
             */
            error InvalidERC721TransferAmount();
            /**
             * @dev Revert with an error when attempting to fulfill an order where an
             *      item has an amount of zero.
             */
            error MissingItemAmount();
            /**
             * @dev Revert with an error when attempting to fulfill an order where an
             *      item has unused parameters. This includes both the token and the
             *      identifier parameters for native transfers as well as the identifier
             *      parameter for ERC20 transfers. Note that the conduit does not
             *      perform this check, leaving it up to the calling channel to enforce
             *      when desired.
             */
            error UnusedItemParameters();
            /**
             * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token
             *      transfer reverts.
             *
             * @param token      The token for which the transfer was attempted.
             * @param from       The source of the attempted transfer.
             * @param to         The recipient of the attempted transfer.
             * @param identifier The identifier for the attempted transfer.
             * @param amount     The amount for the attempted transfer.
             */
            error TokenTransferGenericFailure(
                address token,
                address from,
                address to,
                uint256 identifier,
                uint256 amount
            );
            /**
             * @dev Revert with an error when a batch ERC1155 token transfer reverts.
             *
             * @param token       The token for which the transfer was attempted.
             * @param from        The source of the attempted transfer.
             * @param to          The recipient of the attempted transfer.
             * @param identifiers The identifiers for the attempted transfer.
             * @param amounts     The amounts for the attempted transfer.
             */
            error ERC1155BatchTransferGenericFailure(
                address token,
                address from,
                address to,
                uint256[] identifiers,
                uint256[] amounts
            );
            /**
             * @dev Revert with an error when an ERC20 token transfer returns a falsey
             *      value.
             *
             * @param token      The token for which the ERC20 transfer was attempted.
             * @param from       The source of the attempted ERC20 transfer.
             * @param to         The recipient of the attempted ERC20 transfer.
             * @param amount     The amount for the attempted ERC20 transfer.
             */
            error BadReturnValueFromERC20OnTransfer(
                address token,
                address from,
                address to,
                uint256 amount
            );
            /**
             * @dev Revert with an error when an account being called as an assumed
             *      contract does not have code and returns no data.
             *
             * @param account The account that should contain code.
             */
            error NoContract(address account);
            /**
             * @dev Revert with an error when attempting to execute an 1155 batch
             *      transfer using calldata not produced by default ABI encoding or with
             *      different lengths for ids and amounts arrays.
             */
            error Invalid1155BatchTransferEncoding();
        }
        

        File 4 of 5: ERC721CreatorImplementation
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
        import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
        import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
        import "./IAdminControl.sol";
        abstract contract AdminControlUpgradeable is OwnableUpgradeable, IAdminControl, ERC165 {
            using EnumerableSet for EnumerableSet.AddressSet;
            // Track registered admins
            EnumerableSet.AddressSet private _admins;
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                return interfaceId == type(IAdminControl).interfaceId
                    || super.supportsInterface(interfaceId);
            }
            /**
             * @dev Only allows approved admins to call the specified function
             */
            modifier adminRequired() {
                require(owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin");
                _;
            }   
            /**
             * @dev See {IAdminControl-getAdmins}.
             */
            function getAdmins() external view override returns (address[] memory admins) {
                admins = new address[](_admins.length());
                for (uint i = 0; i < _admins.length(); i++) {
                    admins[i] = _admins.at(i);
                }
                return admins;
            }
            /**
             * @dev See {IAdminControl-approveAdmin}.
             */
            function approveAdmin(address admin) external override onlyOwner {
                if (!_admins.contains(admin)) {
                    emit AdminApproved(admin, msg.sender);
                    _admins.add(admin);
                }
            }
            /**
             * @dev See {IAdminControl-revokeAdmin}.
             */
            function revokeAdmin(address admin) external override onlyOwner {
                if (_admins.contains(admin)) {
                    emit AdminRevoked(admin, msg.sender);
                    _admins.remove(admin);
                }
            }
            /**
             * @dev See {IAdminControl-isAdmin}.
             */
            function isAdmin(address admin) public override view returns (bool) {
                return (owner() == admin || _admins.contains(admin));
            }
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Interface for admin control
         */
        interface IAdminControl is IERC165 {
            event AdminApproved(address indexed account, address indexed sender);
            event AdminRevoked(address indexed account, address indexed sender);
            /**
             * @dev gets address of all admins
             */
            function getAdmins() external view returns (address[] memory);
            /**
             * @dev add an admin.  Can only be called by contract owner.
             */
            function approveAdmin(address admin) external;
            /**
             * @dev remove an admin.  Can only be called by contract owner.
             */
            function revokeAdmin(address admin) external;
            /**
             * @dev checks whether or not given address is an admin
             * Returns True if they are
             */
            function isAdmin(address admin) external view returns (bool);
        }// SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
        pragma solidity ^0.8.0;
        import "../utils/ContextUpgradeable.sol";
        import "../proxy/utils/Initializable.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            function __Ownable_init() internal onlyInitializing {
                __Ownable_init_unchained();
            }
            function __Ownable_init_unchained() internal onlyInitializing {
                _transferOwnership(_msgSender());
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                _checkOwner();
                _;
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if the sender is not the owner.
             */
            function _checkOwner() internal view virtual {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _transferOwnership(address(0));
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                _transferOwnership(newOwner);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Internal function without access restriction.
             */
            function _transferOwnership(address newOwner) internal virtual {
                address oldOwner = _owner;
                _owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[49] private __gap;
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
        pragma solidity ^0.8.2;
        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]
         * ```
         * 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) || (!AddressUpgradeable.isContract(address(this)) && _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
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
        pragma solidity ^0.8.1;
        /**
         * @dev Collection of functions related to the address type
         */
        library AddressUpgradeable {
            /**
             * @dev Returns true if `account` is a contract.
             *
             * [IMPORTANT]
             * ====
             * It is unsafe to assume that an address for which this function returns
             * false is an externally-owned account (EOA) and not a contract.
             *
             * Among others, `isContract` will return false for the following
             * types of addresses:
             *
             *  - an externally-owned account
             *  - a contract in construction
             *  - an address where a contract will be created
             *  - an address where a contract lived, but was destroyed
             * ====
             *
             * [IMPORTANT]
             * ====
             * You shouldn't rely on `isContract` to protect against flash loan attacks!
             *
             * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
             * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
             * constructor.
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize/address.code.length, which returns 0
                // for contracts in construction, since the code is only stored at the end
                // of the constructor execution.
                return account.code.length > 0;
            }
            /**
             * @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://diligence.consensys.net/posts/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.5.11/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 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 isContract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        require(isContract(target), "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
        // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
        pragma solidity ^0.8.0;
        import "../proxy/utils/Initializable.sol";
        /**
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract ContextUpgradeable is Initializable {
            function __Context_init() internal onlyInitializing {
            }
            function __Context_init_unchained() internal onlyInitializing {
            }
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                return msg.data;
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[50] private __gap;
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Contract module that helps prevent reentrant calls to a function.
         *
         * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
         * available, which can be applied to functions to make sure there are no nested
         * (reentrant) calls to them.
         *
         * Note that because there is a single `nonReentrant` guard, functions marked as
         * `nonReentrant` may not call one another. This can be worked around by making
         * those functions `private`, and then adding `external` `nonReentrant` entry
         * points to them.
         *
         * TIP: If you would like to learn more about reentrancy and alternative ways
         * to protect against it, check out our blog post
         * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
         */
        abstract contract ReentrancyGuard {
            // Booleans are more expensive than uint256 or any type that takes up a full
            // word because each write operation emits an extra SLOAD to first read the
            // slot's contents, replace the bits taken up by the boolean, and then write
            // back. This is the compiler's defense against contract upgrades and
            // pointer aliasing, and it cannot be disabled.
            // The values being non-zero value makes deployment a bit more expensive,
            // but in exchange the refund on every call to nonReentrant will be lower in
            // amount. Since refunds are capped to a percentage of the total
            // transaction's gas, it is best to keep them low in cases like this one, to
            // increase the likelihood of the full refund coming into effect.
            uint256 private constant _NOT_ENTERED = 1;
            uint256 private constant _ENTERED = 2;
            uint256 private _status;
            constructor() {
                _status = _NOT_ENTERED;
            }
            /**
             * @dev Prevents a contract from calling itself, directly or indirectly.
             * Calling a `nonReentrant` function from another `nonReentrant`
             * function is not supported. It is possible to prevent this from happening
             * by making the `nonReentrant` function external, and making it call a
             * `private` function that does the actual work.
             */
            modifier nonReentrant() {
                _nonReentrantBefore();
                _;
                _nonReentrantAfter();
            }
            function _nonReentrantBefore() private {
                // On the first call to nonReentrant, _status will be _NOT_ENTERED
                require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                // Any calls to nonReentrant after this point will fail
                _status = _ENTERED;
            }
            function _nonReentrantAfter() private {
                // By storing the original value once again, a refund is triggered (see
                // https://eips.ethereum.org/EIPS/eip-2200)
                _status = _NOT_ENTERED;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
        pragma solidity ^0.8.0;
        import "../IERC721.sol";
        /**
         * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
         * @dev See https://eips.ethereum.org/EIPS/eip-721
         */
        interface IERC721Metadata is IERC721 {
            /**
             * @dev Returns the token collection name.
             */
            function name() external view returns (string memory);
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() external view returns (string memory);
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            function tokenURI(uint256 tokenId) external view returns (string memory);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
        pragma solidity ^0.8.0;
        import "../../utils/introspection/IERC165.sol";
        /**
         * @dev Required interface of an ERC721 compliant contract.
         */
        interface IERC721 is IERC165 {
            /**
             * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
             */
            event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
             */
            event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
             */
            event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            /**
             * @dev Returns the number of tokens in ``owner``'s account.
             */
            function balanceOf(address owner) external view returns (uint256 balance);
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) external view returns (address owner);
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes calldata data
            ) external;
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
             * are aware of the ERC721 protocol to prevent tokens from being forever locked.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external;
            /**
             * @dev Transfers `tokenId` token from `from` to `to`.
             *
             * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
             * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
             * understand this adds an external call which potentially creates a reentrancy vulnerability.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external;
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function approve(address to, uint256 tokenId) external;
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool _approved) external;
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) external view returns (address operator);
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}
             */
            function isApprovedForAll(address owner, address operator) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
        pragma solidity ^0.8.0;
        /**
         * @title ERC721 token receiver interface
         * @dev Interface for any contract that wants to support safeTransfers
         * from ERC721 asset contracts.
         */
        interface IERC721Receiver {
            /**
             * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
             * by `operator` from `from`, this function is called.
             *
             * It must return its Solidity selector to confirm the token transfer.
             * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
             *
             * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
             */
            function onERC721Received(
                address operator,
                address from,
                uint256 tokenId,
                bytes calldata data
            ) external returns (bytes4);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
        pragma solidity ^0.8.1;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
            /**
             * @dev Returns true if `account` is a contract.
             *
             * [IMPORTANT]
             * ====
             * It is unsafe to assume that an address for which this function returns
             * false is an externally-owned account (EOA) and not a contract.
             *
             * Among others, `isContract` will return false for the following
             * types of addresses:
             *
             *  - an externally-owned account
             *  - a contract in construction
             *  - an address where a contract will be created
             *  - an address where a contract lived, but was destroyed
             * ====
             *
             * [IMPORTANT]
             * ====
             * You shouldn't rely on `isContract` to protect against flash loan attacks!
             *
             * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
             * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
             * constructor.
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize/address.code.length, which returns 0
                // for contracts in construction, since the code is only stored at the end
                // of the constructor execution.
                return account.code.length > 0;
            }
            /**
             * @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://diligence.consensys.net/posts/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.5.11/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 isContract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        require(isContract(target), "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
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
        pragma solidity ^0.8.0;
        import "./IERC165.sol";
        /**
         * @dev Implementation of the {IERC165} interface.
         *
         * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
         * for the additional interface id that will be supported. For example:
         *
         * ```solidity
         * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
         *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
         * }
         * ```
         *
         * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
         */
        abstract contract ERC165 is IERC165 {
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                return interfaceId == type(IERC165).interfaceId;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol)
        pragma solidity ^0.8.0;
        import "./IERC165.sol";
        /**
         * @dev Library used to query support of an interface declared via {IERC165}.
         *
         * Note that these functions return the actual result of the query: they do not
         * `revert` if an interface is not supported. It is up to the caller to decide
         * what to do in these cases.
         */
        library ERC165Checker {
            // As per the EIP-165 spec, no interface should ever match 0xffffffff
            bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
            /**
             * @dev Returns true if `account` supports the {IERC165} interface.
             */
            function supportsERC165(address account) internal view returns (bool) {
                // Any contract that implements ERC165 must explicitly indicate support of
                // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                return
                    supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
                    !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
            }
            /**
             * @dev Returns true if `account` supports the interface defined by
             * `interfaceId`. Support for {IERC165} itself is queried automatically.
             *
             * See {IERC165-supportsInterface}.
             */
            function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                // query support of both ERC165 as per the spec and support of _interfaceId
                return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
            }
            /**
             * @dev Returns a boolean array where each value corresponds to the
             * interfaces passed in and whether they're supported or not. This allows
             * you to batch check interfaces for a contract where your expectation
             * is that some interfaces may not be supported.
             *
             * See {IERC165-supportsInterface}.
             *
             * _Available since v3.4._
             */
            function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
                internal
                view
                returns (bool[] memory)
            {
                // an array of booleans corresponding to interfaceIds and whether they're supported or not
                bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
                // query support of ERC165 itself
                if (supportsERC165(account)) {
                    // query support of each interface in interfaceIds
                    for (uint256 i = 0; i < interfaceIds.length; i++) {
                        interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
                    }
                }
                return interfaceIdsSupported;
            }
            /**
             * @dev Returns true if `account` supports all the interfaces defined in
             * `interfaceIds`. Support for {IERC165} itself is queried automatically.
             *
             * Batch-querying can lead to gas savings by skipping repeated checks for
             * {IERC165} support.
             *
             * See {IERC165-supportsInterface}.
             */
            function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                // query support of ERC165 itself
                if (!supportsERC165(account)) {
                    return false;
                }
                // query support of each interface in interfaceIds
                for (uint256 i = 0; i < interfaceIds.length; i++) {
                    if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                        return false;
                    }
                }
                // all interfaces supported
                return true;
            }
            /**
             * @notice Query if a contract implements an interface, does not check ERC165 support
             * @param account The address of the contract to query for support of an interface
             * @param interfaceId The interface identifier, as specified in ERC-165
             * @return true if the contract at account indicates support of the interface with
             * identifier interfaceId, false otherwise
             * @dev Assumes that account contains a contract that supports ERC165, otherwise
             * the behavior of this method is undefined. This precondition can be checked
             * with {supportsERC165}.
             * Interface identification is specified in ERC-165.
             */
            function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
                // prepare call
                bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
                // perform static call
                bool success;
                uint256 returnSize;
                uint256 returnValue;
                assembly {
                    success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
                    returnSize := returndatasize()
                    returnValue := mload(0x00)
                }
                return success && returnSize >= 0x20 && returnValue > 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
        pragma solidity ^0.8.0;
        /**
         * @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
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Standard math utilities missing in the Solidity language.
         */
        library Math {
            enum Rounding {
                Down, // Toward negative infinity
                Up, // Toward infinity
                Zero // Toward zero
            }
            /**
             * @dev Returns the largest of two numbers.
             */
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a > b ? a : b;
            }
            /**
             * @dev Returns the smallest of two numbers.
             */
            function min(uint256 a, uint256 b) internal pure returns (uint256) {
                return a < b ? a : b;
            }
            /**
             * @dev Returns the average of two numbers. The result is rounded towards
             * zero.
             */
            function average(uint256 a, uint256 b) internal pure returns (uint256) {
                // (a + b) / 2 can overflow.
                return (a & b) + (a ^ b) / 2;
            }
            /**
             * @dev Returns the ceiling of the division of two numbers.
             *
             * This differs from standard division with `/` in that it rounds up instead
             * of rounding down.
             */
            function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                // (a + b - 1) / b can overflow on addition, so we distribute.
                return a == 0 ? 0 : (a - 1) / b + 1;
            }
            /**
             * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
             * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
             * with further edits by Uniswap Labs also under MIT license.
             */
            function mulDiv(
                uint256 x,
                uint256 y,
                uint256 denominator
            ) internal pure returns (uint256 result) {
                unchecked {
                    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                    // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                    // variables such that product = prod1 * 2^256 + prod0.
                    uint256 prod0; // Least significant 256 bits of the product
                    uint256 prod1; // Most significant 256 bits of the product
                    assembly {
                        let mm := mulmod(x, y, not(0))
                        prod0 := mul(x, y)
                        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                    }
                    // Handle non-overflow cases, 256 by 256 division.
                    if (prod1 == 0) {
                        return prod0 / denominator;
                    }
                    // Make sure the result is less than 2^256. Also prevents denominator == 0.
                    require(denominator > prod1);
                    ///////////////////////////////////////////////
                    // 512 by 256 division.
                    ///////////////////////////////////////////////
                    // Make division exact by subtracting the remainder from [prod1 prod0].
                    uint256 remainder;
                    assembly {
                        // Compute remainder using mulmod.
                        remainder := mulmod(x, y, denominator)
                        // Subtract 256 bit number from 512 bit number.
                        prod1 := sub(prod1, gt(remainder, prod0))
                        prod0 := sub(prod0, remainder)
                    }
                    // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                    // See https://cs.stackexchange.com/q/138556/92363.
                    // Does not overflow because the denominator cannot be zero at this stage in the function.
                    uint256 twos = denominator & (~denominator + 1);
                    assembly {
                        // Divide denominator by twos.
                        denominator := div(denominator, twos)
                        // Divide [prod1 prod0] by twos.
                        prod0 := div(prod0, twos)
                        // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                        twos := add(div(sub(0, twos), twos), 1)
                    }
                    // Shift in bits from prod1 into prod0.
                    prod0 |= prod1 * twos;
                    // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                    // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                    // four bits. That is, denominator * inv = 1 mod 2^4.
                    uint256 inverse = (3 * denominator) ^ 2;
                    // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                    // in modular arithmetic, doubling the correct bits in each step.
                    inverse *= 2 - denominator * inverse; // inverse mod 2^8
                    inverse *= 2 - denominator * inverse; // inverse mod 2^16
                    inverse *= 2 - denominator * inverse; // inverse mod 2^32
                    inverse *= 2 - denominator * inverse; // inverse mod 2^64
                    inverse *= 2 - denominator * inverse; // inverse mod 2^128
                    inverse *= 2 - denominator * inverse; // inverse mod 2^256
                    // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                    // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                    // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                    // is no longer required.
                    result = prod0 * inverse;
                    return result;
                }
            }
            /**
             * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
             */
            function mulDiv(
                uint256 x,
                uint256 y,
                uint256 denominator,
                Rounding rounding
            ) internal pure returns (uint256) {
                uint256 result = mulDiv(x, y, denominator);
                if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                    result += 1;
                }
                return result;
            }
            /**
             * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
             *
             * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
             */
            function sqrt(uint256 a) internal pure returns (uint256) {
                if (a == 0) {
                    return 0;
                }
                // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                //
                // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                //
                // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                //
                // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                uint256 result = 1 << (log2(a) >> 1);
                // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                // into the expected uint128 result.
                unchecked {
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    return min(result, a / result);
                }
            }
            /**
             * @notice Calculates sqrt(a), following the selected rounding direction.
             */
            function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = sqrt(a);
                    return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 2, rounded down, of a positive value.
             * Returns 0 if given 0.
             */
            function log2(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 128;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 64;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 32;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 16;
                    }
                    if (value >> 8 > 0) {
                        value >>= 8;
                        result += 8;
                    }
                    if (value >> 4 > 0) {
                        value >>= 4;
                        result += 4;
                    }
                    if (value >> 2 > 0) {
                        value >>= 2;
                        result += 2;
                    }
                    if (value >> 1 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log2(value);
                    return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 10, rounded down, of a positive value.
             * Returns 0 if given 0.
             */
            function log10(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >= 10**64) {
                        value /= 10**64;
                        result += 64;
                    }
                    if (value >= 10**32) {
                        value /= 10**32;
                        result += 32;
                    }
                    if (value >= 10**16) {
                        value /= 10**16;
                        result += 16;
                    }
                    if (value >= 10**8) {
                        value /= 10**8;
                        result += 8;
                    }
                    if (value >= 10**4) {
                        value /= 10**4;
                        result += 4;
                    }
                    if (value >= 10**2) {
                        value /= 10**2;
                        result += 2;
                    }
                    if (value >= 10**1) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log10(value);
                    return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 256, rounded down, of a positive value.
             * Returns 0 if given 0.
             *
             * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
             */
            function log256(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 16;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 8;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 4;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 2;
                    }
                    if (value >> 8 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log256(value);
                    return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
        pragma solidity ^0.8.0;
        import "./math/Math.sol";
        /**
         * @dev String operations.
         */
        library Strings {
            bytes16 private constant _SYMBOLS = "0123456789abcdef";
            uint8 private constant _ADDRESS_LENGTH = 20;
            /**
             * @dev Converts a `uint256` to its ASCII `string` decimal representation.
             */
            function toString(uint256 value) internal pure returns (string memory) {
                unchecked {
                    uint256 length = Math.log10(value) + 1;
                    string memory buffer = new string(length);
                    uint256 ptr;
                    /// @solidity memory-safe-assembly
                    assembly {
                        ptr := add(buffer, add(32, length))
                    }
                    while (true) {
                        ptr--;
                        /// @solidity memory-safe-assembly
                        assembly {
                            mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                        }
                        value /= 10;
                        if (value == 0) break;
                    }
                    return buffer;
                }
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
             */
            function toHexString(uint256 value) internal pure returns (string memory) {
                unchecked {
                    return toHexString(value, Math.log256(value) + 1);
                }
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
             */
            function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                bytes memory buffer = new bytes(2 * length + 2);
                buffer[0] = "0";
                buffer[1] = "x";
                for (uint256 i = 2 * length + 1; i > 1; --i) {
                    buffer[i] = _SYMBOLS[value & 0xf];
                    value >>= 4;
                }
                require(value == 0, "Strings: hex length insufficient");
                return string(buffer);
            }
            /**
             * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
             */
            function toHexString(address addr) internal pure returns (string memory) {
                return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
        // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
        pragma solidity ^0.8.0;
        /**
         * @dev Library for managing
         * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
         * types.
         *
         * Sets have the following properties:
         *
         * - Elements are added, removed, and checked for existence in constant time
         * (O(1)).
         * - Elements are enumerated in O(n). No guarantees are made on the ordering.
         *
         * ```
         * contract Example {
         *     // Add the library methods
         *     using EnumerableSet for EnumerableSet.AddressSet;
         *
         *     // Declare a set state variable
         *     EnumerableSet.AddressSet private mySet;
         * }
         * ```
         *
         * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
         * and `uint256` (`UintSet`) are supported.
         *
         * [WARNING]
         * ====
         * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
         * unusable.
         * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
         *
         * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
         * array of EnumerableSet.
         * ====
         */
        library EnumerableSet {
            // To implement this library for multiple types with as little code
            // repetition as possible, we write it in terms of a generic Set type with
            // bytes32 values.
            // The Set implementation uses private functions, and user-facing
            // implementations (such as AddressSet) are just wrappers around the
            // underlying Set.
            // This means that we can only create new EnumerableSets for types that fit
            // in bytes32.
            struct Set {
                // Storage of set values
                bytes32[] _values;
                // Position of the value in the `values` array, plus 1 because index 0
                // means a value is not in the set.
                mapping(bytes32 => uint256) _indexes;
            }
            /**
             * @dev Add a value to a set. O(1).
             *
             * Returns true if the value was added to the set, that is if it was not
             * already present.
             */
            function _add(Set storage set, bytes32 value) private returns (bool) {
                if (!_contains(set, value)) {
                    set._values.push(value);
                    // The value is stored at length-1, but we add 1 to all indexes
                    // and use 0 as a sentinel value
                    set._indexes[value] = set._values.length;
                    return true;
                } else {
                    return false;
                }
            }
            /**
             * @dev Removes a value from a set. O(1).
             *
             * Returns true if the value was removed from the set, that is if it was
             * present.
             */
            function _remove(Set storage set, bytes32 value) private returns (bool) {
                // We read and store the value's index to prevent multiple reads from the same storage slot
                uint256 valueIndex = set._indexes[value];
                if (valueIndex != 0) {
                    // Equivalent to contains(set, value)
                    // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                    // the array, and then remove the last element (sometimes called as 'swap and pop').
                    // This modifies the order of the array, as noted in {at}.
                    uint256 toDeleteIndex = valueIndex - 1;
                    uint256 lastIndex = set._values.length - 1;
                    if (lastIndex != toDeleteIndex) {
                        bytes32 lastValue = set._values[lastIndex];
                        // Move the last value to the index where the value to delete is
                        set._values[toDeleteIndex] = lastValue;
                        // Update the index for the moved value
                        set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
                    }
                    // Delete the slot where the moved value was stored
                    set._values.pop();
                    // Delete the index for the deleted slot
                    delete set._indexes[value];
                    return true;
                } else {
                    return false;
                }
            }
            /**
             * @dev Returns true if the value is in the set. O(1).
             */
            function _contains(Set storage set, bytes32 value) private view returns (bool) {
                return set._indexes[value] != 0;
            }
            /**
             * @dev Returns the number of values on the set. O(1).
             */
            function _length(Set storage set) private view returns (uint256) {
                return set._values.length;
            }
            /**
             * @dev Returns the value stored at position `index` in the set. O(1).
             *
             * Note that there are no guarantees on the ordering of values inside the
             * array, and it may change when more values are added or removed.
             *
             * Requirements:
             *
             * - `index` must be strictly less than {length}.
             */
            function _at(Set storage set, uint256 index) private view returns (bytes32) {
                return set._values[index];
            }
            /**
             * @dev Return the entire set in an array
             *
             * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
             * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
             * this function has an unbounded cost, and using it as part of a state-changing function may render the function
             * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
             */
            function _values(Set storage set) private view returns (bytes32[] memory) {
                return set._values;
            }
            // Bytes32Set
            struct Bytes32Set {
                Set _inner;
            }
            /**
             * @dev Add a value to a set. O(1).
             *
             * Returns true if the value was added to the set, that is if it was not
             * already present.
             */
            function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                return _add(set._inner, value);
            }
            /**
             * @dev Removes a value from a set. O(1).
             *
             * Returns true if the value was removed from the set, that is if it was
             * present.
             */
            function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                return _remove(set._inner, value);
            }
            /**
             * @dev Returns true if the value is in the set. O(1).
             */
            function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
                return _contains(set._inner, value);
            }
            /**
             * @dev Returns the number of values in the set. O(1).
             */
            function length(Bytes32Set storage set) internal view returns (uint256) {
                return _length(set._inner);
            }
            /**
             * @dev Returns the value stored at position `index` in the set. O(1).
             *
             * Note that there are no guarantees on the ordering of values inside the
             * array, and it may change when more values are added or removed.
             *
             * Requirements:
             *
             * - `index` must be strictly less than {length}.
             */
            function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
                return _at(set._inner, index);
            }
            /**
             * @dev Return the entire set in an array
             *
             * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
             * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
             * this function has an unbounded cost, and using it as part of a state-changing function may render the function
             * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
             */
            function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
                bytes32[] memory store = _values(set._inner);
                bytes32[] memory result;
                /// @solidity memory-safe-assembly
                assembly {
                    result := store
                }
                return result;
            }
            // AddressSet
            struct AddressSet {
                Set _inner;
            }
            /**
             * @dev Add a value to a set. O(1).
             *
             * Returns true if the value was added to the set, that is if it was not
             * already present.
             */
            function add(AddressSet storage set, address value) internal returns (bool) {
                return _add(set._inner, bytes32(uint256(uint160(value))));
            }
            /**
             * @dev Removes a value from a set. O(1).
             *
             * Returns true if the value was removed from the set, that is if it was
             * present.
             */
            function remove(AddressSet storage set, address value) internal returns (bool) {
                return _remove(set._inner, bytes32(uint256(uint160(value))));
            }
            /**
             * @dev Returns true if the value is in the set. O(1).
             */
            function contains(AddressSet storage set, address value) internal view returns (bool) {
                return _contains(set._inner, bytes32(uint256(uint160(value))));
            }
            /**
             * @dev Returns the number of values in the set. O(1).
             */
            function length(AddressSet storage set) internal view returns (uint256) {
                return _length(set._inner);
            }
            /**
             * @dev Returns the value stored at position `index` in the set. O(1).
             *
             * Note that there are no guarantees on the ordering of values inside the
             * array, and it may change when more values are added or removed.
             *
             * Requirements:
             *
             * - `index` must be strictly less than {length}.
             */
            function at(AddressSet storage set, uint256 index) internal view returns (address) {
                return address(uint160(uint256(_at(set._inner, index))));
            }
            /**
             * @dev Return the entire set in an array
             *
             * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
             * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
             * this function has an unbounded cost, and using it as part of a state-changing function may render the function
             * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
             */
            function values(AddressSet storage set) internal view returns (address[] memory) {
                bytes32[] memory store = _values(set._inner);
                address[] memory result;
                /// @solidity memory-safe-assembly
                assembly {
                    result := store
                }
                return result;
            }
            // UintSet
            struct UintSet {
                Set _inner;
            }
            /**
             * @dev Add a value to a set. O(1).
             *
             * Returns true if the value was added to the set, that is if it was not
             * already present.
             */
            function add(UintSet storage set, uint256 value) internal returns (bool) {
                return _add(set._inner, bytes32(value));
            }
            /**
             * @dev Removes a value from a set. O(1).
             *
             * Returns true if the value was removed from the set, that is if it was
             * present.
             */
            function remove(UintSet storage set, uint256 value) internal returns (bool) {
                return _remove(set._inner, bytes32(value));
            }
            /**
             * @dev Returns true if the value is in the set. O(1).
             */
            function contains(UintSet storage set, uint256 value) internal view returns (bool) {
                return _contains(set._inner, bytes32(value));
            }
            /**
             * @dev Returns the number of values in the set. O(1).
             */
            function length(UintSet storage set) internal view returns (uint256) {
                return _length(set._inner);
            }
            /**
             * @dev Returns the value stored at position `index` in the set. O(1).
             *
             * Note that there are no guarantees on the ordering of values inside the
             * array, and it may change when more values are added or removed.
             *
             * Requirements:
             *
             * - `index` must be strictly less than {length}.
             */
            function at(UintSet storage set, uint256 index) internal view returns (uint256) {
                return uint256(_at(set._inner, index));
            }
            /**
             * @dev Return the entire set in an array
             *
             * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
             * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
             * this function has an unbounded cost, and using it as part of a state-changing function may render the function
             * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
             */
            function values(UintSet storage set) internal view returns (uint256[] memory) {
                bytes32[] memory store = _values(set._inner);
                uint256[] memory result;
                /// @solidity memory-safe-assembly
                assembly {
                    result := store
                }
                return result;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
        import "@openzeppelin/contracts/utils/Strings.sol";
        import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
        import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
        import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
        import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
        import "../extensions/ICreatorExtensionTokenURI.sol";
        import "../extensions/ICreatorExtensionRoyalties.sol";
        import "./ICreatorCore.sol";
        /**
         * @dev Core creator implementation
         */
        abstract contract CreatorCore is ReentrancyGuard, ICreatorCore, ERC165 {
            using Strings for uint256;
            using EnumerableSet for EnumerableSet.AddressSet;
            using AddressUpgradeable for address;
            uint256 internal _tokenCount = 0;
            // Base approve transfers address location
            address internal _approveTransferBase;
            // Track registered extensions data
            EnumerableSet.AddressSet internal _extensions;
            EnumerableSet.AddressSet internal _blacklistedExtensions;
            // The baseURI for a given extension
            mapping (address => string) private _extensionBaseURI;
            mapping (address => bool) private _extensionBaseURIIdentical;
            // The prefix for any tokens with a uri configured
            mapping (address => string) private _extensionURIPrefix;
            // Mapping for individual token URIs
            mapping (uint256 => string) internal _tokenURIs;
            // Royalty configurations
            struct RoyaltyConfig {
                address payable receiver;
                uint16 bps;
            }
            mapping (address => RoyaltyConfig[]) internal _extensionRoyalty;
            mapping (uint256 => RoyaltyConfig[]) internal _tokenRoyalty;
            bytes4 private constant _CREATOR_CORE_V1 = 0x28f10a21;
            /**
             * External interface identifiers for royalties
             */
            /**
             *  @dev CreatorCore
             *
             *  bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6
             *
             *  => 0xbb3bafd6 = 0xbb3bafd6
             */
            bytes4 private constant _INTERFACE_ID_ROYALTIES_CREATORCORE = 0xbb3bafd6;
            /**
             *  @dev Rarible: RoyaltiesV1
             *
             *  bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
             *  bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
             *
             *  => 0xb9c4d9fb ^ 0x0ebd4c7f = 0xb7799584
             */
            bytes4 private constant _INTERFACE_ID_ROYALTIES_RARIBLE = 0xb7799584;
            /**
             *  @dev Foundation
             *
             *  bytes4(keccak256('getFees(uint256)')) == 0xd5a06d4c
             *
             *  => 0xd5a06d4c = 0xd5a06d4c
             */
            bytes4 private constant _INTERFACE_ID_ROYALTIES_FOUNDATION = 0xd5a06d4c;
            /**
             *  @dev EIP-2981
             *
             * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
             *
             * => 0x2a55205a = 0x2a55205a
             */
            bytes4 private constant _INTERFACE_ID_ROYALTIES_EIP2981 = 0x2a55205a;
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                return interfaceId == type(ICreatorCore).interfaceId || interfaceId == _CREATOR_CORE_V1 || super.supportsInterface(interfaceId)
                    || interfaceId == _INTERFACE_ID_ROYALTIES_CREATORCORE || interfaceId == _INTERFACE_ID_ROYALTIES_RARIBLE
                    || interfaceId == _INTERFACE_ID_ROYALTIES_FOUNDATION || interfaceId == _INTERFACE_ID_ROYALTIES_EIP2981;
            }
            /**
             * @dev Only allows registered extensions to call the specified function
             */
            function requireExtension() internal view {
                require(_extensions.contains(msg.sender), "Must be registered extension");
            }
            /**
             * @dev Only allows non-blacklisted extensions
             */
            function requireNonBlacklist(address extension) internal view {
                require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
            }   
            /**
             * @dev See {ICreatorCore-getExtensions}.
             */
            function getExtensions() external view override returns (address[] memory extensions) {
                extensions = new address[](_extensions.length());
                for (uint i; i < _extensions.length();) {
                    extensions[i] = _extensions.at(i);
                    unchecked { ++i; }
                }
                return extensions;
            }
            /**
             * @dev Register an extension
             */
            function _registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) internal virtual {
                require(extension != address(this) && extension.isContract(), "Invalid");
                emit ExtensionRegistered(extension, msg.sender);
                _extensionBaseURI[extension] = baseURI;
                _extensionBaseURIIdentical[extension] = baseURIIdentical;
                _extensions.add(extension);
                _setApproveTransferExtension(extension, true);
            }
            /**
             * @dev See {ICreatorCore-setApproveTransferExtension}.
             */
            function setApproveTransferExtension(bool enabled) external override {
                requireExtension();
                _setApproveTransferExtension(msg.sender, enabled);
            }
            /**
             * @dev Set whether or not tokens minted by the extension defers transfer approvals to the extension
             */
            function _setApproveTransferExtension(address extension, bool enabled) internal virtual;
            /**
             * @dev Unregister an extension
             */
            function _unregisterExtension(address extension) internal {
                emit ExtensionUnregistered(extension, msg.sender);
                _extensions.remove(extension);
            }
            /**
             * @dev Blacklist an extension
             */
            function _blacklistExtension(address extension) internal {
               require(extension != address(0) && extension != address(this), "Cannot blacklist yourself");
               if (_extensions.contains(extension)) {
                   emit ExtensionUnregistered(extension, msg.sender);
                   _extensions.remove(extension);
               }
               if (!_blacklistedExtensions.contains(extension)) {
                   emit ExtensionBlacklisted(extension, msg.sender);
                   _blacklistedExtensions.add(extension);
               }
            }
            /**
             * @dev Set base token uri for an extension
             */
            function _setBaseTokenURIExtension(string calldata uri, bool identical) internal {
                _extensionBaseURI[msg.sender] = uri;
                _extensionBaseURIIdentical[msg.sender] = identical;
            }
            /**
             * @dev Set token uri prefix for an extension
             */
            function _setTokenURIPrefixExtension(string calldata prefix) internal {
                _extensionURIPrefix[msg.sender] = prefix;
            }
            /**
             * @dev Set token uri for a token of an extension
             */
            function _setTokenURIExtension(uint256 tokenId, string calldata uri) internal {
                require(_tokenExtension(tokenId) == msg.sender, "Invalid token");
                _tokenURIs[tokenId] = uri;
            }
            /**
             * @dev Set base token uri for tokens with no extension
             */
            function _setBaseTokenURI(string calldata uri) internal {
                _extensionBaseURI[address(0)] = uri;
            }
            /**
             * @dev Set token uri prefix for tokens with no extension
             */
            function _setTokenURIPrefix(string calldata prefix) internal {
                _extensionURIPrefix[address(0)] = prefix;
            }
            /**
             * @dev Set token uri for a token with no extension
             */
            function _setTokenURI(uint256 tokenId, string calldata uri) internal {
                require(tokenId > 0 && tokenId <= _tokenCount && _tokenExtension(tokenId) == address(0), "Invalid token");
                _tokenURIs[tokenId] = uri;
            }
            /**
             * @dev Retrieve a token's URI
             */
            function _tokenURI(uint256 tokenId) internal view returns (string memory) {
                require(tokenId > 0 && tokenId <= _tokenCount, "Invalid token");
                address extension = _tokenExtension(tokenId);
                require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
                if (bytes(_tokenURIs[tokenId]).length != 0) {
                    if (bytes(_extensionURIPrefix[extension]).length != 0) {
                        return string(abi.encodePacked(_extensionURIPrefix[extension], _tokenURIs[tokenId]));
                    }
                    return _tokenURIs[tokenId];
                }
                if (ERC165Checker.supportsInterface(extension, type(ICreatorExtensionTokenURI).interfaceId)) {
                    return ICreatorExtensionTokenURI(extension).tokenURI(address(this), tokenId);
                }
                if (!_extensionBaseURIIdentical[extension]) {
                    return string(abi.encodePacked(_extensionBaseURI[extension], tokenId.toString()));
                } else {
                    return _extensionBaseURI[extension];
                }
            }
            /**
             * Helper to get royalties for a token
             */
            function _getRoyalties(uint256 tokenId) view internal returns (address payable[] memory receivers, uint256[] memory bps) {
                // Get token level royalties
                RoyaltyConfig[] memory royalties = _tokenRoyalty[tokenId];
                if (royalties.length == 0) {
                    // Get extension specific royalties
                    address extension = _tokenExtension(tokenId);
                    if (extension != address(0)) {
                        if (ERC165Checker.supportsInterface(extension, type(ICreatorExtensionRoyalties).interfaceId)) {
                            (receivers, bps) = ICreatorExtensionRoyalties(extension).getRoyalties(address(this), tokenId);
                            // Extension override exists, just return that
                            if (receivers.length > 0) return (receivers, bps);
                        }
                        royalties = _extensionRoyalty[extension];
                    }
                }
                if (royalties.length == 0) {
                    // Get the default royalty
                    royalties = _extensionRoyalty[address(0)];
                }
                
                if (royalties.length > 0) {
                    receivers = new address payable[](royalties.length);
                    bps = new uint256[](royalties.length);
                    for (uint i; i < royalties.length;) {
                        receivers[i] = royalties[i].receiver;
                        bps[i] = royalties[i].bps;
                        unchecked { ++i; }
                    }
                }
            }
            /**
             * Helper to get royalty receivers for a token
             */
            function _getRoyaltyReceivers(uint256 tokenId) view internal returns (address payable[] memory recievers) {
                (recievers, ) = _getRoyalties(tokenId);
            }
            /**
             * Helper to get royalty basis points for a token
             */
            function _getRoyaltyBPS(uint256 tokenId) view internal returns (uint256[] memory bps) {
                (, bps) = _getRoyalties(tokenId);
            }
            function _getRoyaltyInfo(uint256 tokenId, uint256 value) view internal returns (address receiver, uint256 amount){
                (address payable[] memory receivers, uint256[] memory bps) = _getRoyalties(tokenId);
                require(receivers.length <= 1, "More than 1 royalty receiver");
                
                if (receivers.length == 0) {
                    return (address(this), 0);
                }
                return (receivers[0], bps[0]*value/10000);
            }
            /**
             * Set royalties for a token
             */
            function _setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) internal {
               _checkRoyalties(receivers, basisPoints);
                delete _tokenRoyalty[tokenId];
                _setRoyalties(receivers, basisPoints, _tokenRoyalty[tokenId]);
                emit RoyaltiesUpdated(tokenId, receivers, basisPoints);
            }
            /**
             * Set royalties for all tokens of an extension
             */
            function _setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) internal {
                _checkRoyalties(receivers, basisPoints);
                delete _extensionRoyalty[extension];
                _setRoyalties(receivers, basisPoints, _extensionRoyalty[extension]);
                if (extension == address(0)) {
                    emit DefaultRoyaltiesUpdated(receivers, basisPoints);
                } else {
                    emit ExtensionRoyaltiesUpdated(extension, receivers, basisPoints);
                }
            }
            /**
             * Helper function to check that royalties provided are valid
             */
            function _checkRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) private pure {
                require(receivers.length == basisPoints.length, "Invalid input");
                uint256 totalBasisPoints;
                for (uint i; i < basisPoints.length;) {
                    totalBasisPoints += basisPoints[i];
                    unchecked { ++i; }
                }
                require(totalBasisPoints < 10000, "Invalid total royalties");
            }
            /**
             * Helper function to set royalties
             */
            function _setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints, RoyaltyConfig[] storage royalties) private {
                for (uint i; i < basisPoints.length;) {
                    royalties.push(
                        RoyaltyConfig(
                            {
                                receiver: receivers[i],
                                bps: uint16(basisPoints[i])
                            }
                        )
                    );
                    unchecked { ++i; }
                }
            }
            /**
             * @dev Set the base contract's approve transfer contract location
             */
            function _setApproveTransferBase(address extension) internal {
                _approveTransferBase = extension;
                emit ApproveTransferUpdated(extension);
            }
            /**
             * @dev See {ICreatorCore-getApproveTransfer}.
             */
            function getApproveTransfer() external view override returns (address) {
                return _approveTransferBase;
            }
            /**
             * @dev Get the extension for the given token
             */
            function _tokenExtension(uint256 tokenId) internal virtual view returns(address);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
        import "../extensions/ERC721/IERC721CreatorExtensionApproveTransfer.sol";
        import "../extensions/ERC721/IERC721CreatorExtensionBurnable.sol";
        import "../permissions/ERC721/IERC721CreatorMintPermissions.sol";
        import "./IERC721CreatorCore.sol";
        import "./CreatorCore.sol";
        /**
         * @dev Core ERC721 creator implementation
         */
        abstract contract ERC721CreatorCore is CreatorCore, IERC721CreatorCore {
            uint256 constant public VERSION = 3;
            bytes4 private constant _ERC721_CREATOR_CORE_V1 = 0x9088c207;
            using EnumerableSet for EnumerableSet.AddressSet;
            // Track registered extensions data
            mapping (address => bool) internal _extensionApproveTransfers;
            mapping (address => address) internal _extensionPermissions;
            // For tracking extension indices
            uint16 private _extensionCounter;
            mapping (address => uint16) internal _extensionToIndex;    
            mapping (uint16 => address) internal _indexToExtension;
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(CreatorCore, IERC165) returns (bool) {
                return interfaceId == type(IERC721CreatorCore).interfaceId || interfaceId == _ERC721_CREATOR_CORE_V1 || super.supportsInterface(interfaceId);
            }
            /**
             * @dev See {CreatorCore-_setApproveTransferExtension}
             */
            function _setApproveTransferExtension(address extension, bool enabled) internal override {
                if (ERC165Checker.supportsInterface(extension, type(IERC721CreatorExtensionApproveTransfer).interfaceId)) {
                    _extensionApproveTransfers[extension] = enabled;
                    emit ExtensionApproveTransferUpdated(extension, enabled);
                }
            }
            /**
             * @dev Set mint permissions for an extension
             */
            function _setMintPermissions(address extension, address permissions) internal {
                require(_extensions.contains(extension), "CreatorCore: Invalid extension");
                require(permissions == address(0) || ERC165Checker.supportsInterface(permissions, type(IERC721CreatorMintPermissions).interfaceId), "Invalid address");
                if (_extensionPermissions[extension] != permissions) {
                    _extensionPermissions[extension] = permissions;
                    emit MintPermissionsUpdated(extension, permissions, msg.sender);
                }
            }
            /**
             * If mint permissions have been set for an extension (extensions can mint by default),
             * check if an extension can mint via the permission contract's approveMint function.
             */
            function _checkMintPermissions(address to, uint256 tokenId) internal {
                if (_extensionPermissions[msg.sender] != address(0)) {
                    IERC721CreatorMintPermissions(_extensionPermissions[msg.sender]).approveMint(msg.sender, to, tokenId);
                }
            }
            /**
             * Override for pre mint actions
             */
            function _preMintBase(address, uint256) internal virtual {}
            
            /**
             * Override for pre mint actions for _mintExtension
             */
            function _preMintExtension(address, uint256) internal virtual {}
            /**
             * Post-burning callback and metadata cleanup
             */
            function _postBurn(address owner, uint256 tokenId, address extension) internal virtual {
                // Callback to originating extension if needed
                if (extension != address(0)) {
                   if (ERC165Checker.supportsInterface(extension, type(IERC721CreatorExtensionBurnable).interfaceId)) {
                       IERC721CreatorExtensionBurnable(extension).onBurn(owner, tokenId);
                   }
                }
                // Clear metadata (if any)
                if (bytes(_tokenURIs[tokenId]).length != 0) {
                    delete _tokenURIs[tokenId];
                } 
            }
            /**
             * Approve a transfer
             */
            function _approveTransfer(address from, address to, uint256 tokenId) internal {
                // Do not need to approve mints
                if (from == address(0)) return;
                _approveTransfer(from, to, tokenId, _tokenExtension(tokenId));
            }
            function _approveTransfer(address from, address to, uint256 tokenId, uint16 extensionIndex) internal {
                // Do not need to approve mints
                if (from == address(0)) return;
                _approveTransfer(from, to, tokenId, _indexToExtension[extensionIndex]);
            }
            function _approveTransfer(address from, address to, uint256 tokenId, address extension) internal {
                // Do not need to approve mints
                if (from == address(0)) return;
                if (extension != address(0) && _extensionApproveTransfers[extension]) {
                    require(IERC721CreatorExtensionApproveTransfer(extension).approveTransfer(msg.sender, from, to, tokenId), "Extension approval failure");
                } else if (_approveTransferBase != address(0)) {
                   require(IERC721CreatorExtensionApproveTransfer(_approveTransferBase).approveTransfer(msg.sender, from, to, tokenId), "Extension approval failure");
                }
            }
            /**
             * @dev Register an extension
             */
            function _registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) internal override {
                require(_extensionCounter < 0xFFFF, "Too many extensions");
                if (_extensionToIndex[extension] == 0) {
                    ++_extensionCounter;
                    _extensionToIndex[extension] = _extensionCounter;
                    _indexToExtension[_extensionCounter] = extension;
                }
                super._registerExtension(extension, baseURI, baseURIIdentical);
            }
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Core creator interface
         */
        interface ICreatorCore is IERC165 {
            event ExtensionRegistered(address indexed extension, address indexed sender);
            event ExtensionUnregistered(address indexed extension, address indexed sender);
            event ExtensionBlacklisted(address indexed extension, address indexed sender);
            event MintPermissionsUpdated(address indexed extension, address indexed permissions, address indexed sender);
            event RoyaltiesUpdated(uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints);
            event DefaultRoyaltiesUpdated(address payable[] receivers, uint256[] basisPoints);
            event ApproveTransferUpdated(address extension);
            event ExtensionRoyaltiesUpdated(address indexed extension, address payable[] receivers, uint256[] basisPoints);
            event ExtensionApproveTransferUpdated(address indexed extension, bool enabled);
            /**
             * @dev gets address of all extensions
             */
            function getExtensions() external view returns (address[] memory);
            /**
             * @dev add an extension.  Can only be called by contract owner or admin.
             * extension address must point to a contract implementing ICreatorExtension.
             * Returns True if newly added, False if already added.
             */
            function registerExtension(address extension, string calldata baseURI) external;
            /**
             * @dev add an extension.  Can only be called by contract owner or admin.
             * extension address must point to a contract implementing ICreatorExtension.
             * Returns True if newly added, False if already added.
             */
            function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external;
            /**
             * @dev add an extension.  Can only be called by contract owner or admin.
             * Returns True if removed, False if already removed.
             */
            function unregisterExtension(address extension) external;
            /**
             * @dev blacklist an extension.  Can only be called by contract owner or admin.
             * This function will destroy all ability to reference the metadata of any tokens created
             * by the specified extension. It will also unregister the extension if needed.
             * Returns True if removed, False if already removed.
             */
            function blacklistExtension(address extension) external;
            /**
             * @dev set the baseTokenURI of an extension.  Can only be called by extension.
             */
            function setBaseTokenURIExtension(string calldata uri) external;
            /**
             * @dev set the baseTokenURI of an extension.  Can only be called by extension.
             * For tokens with no uri configured, tokenURI will return "uri+tokenId"
             */
            function setBaseTokenURIExtension(string calldata uri, bool identical) external;
            /**
             * @dev set the common prefix of an extension.  Can only be called by extension.
             * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
             * Useful if you want to use ipfs/arweave
             */
            function setTokenURIPrefixExtension(string calldata prefix) external;
            /**
             * @dev set the tokenURI of a token extension.  Can only be called by extension that minted token.
             */
            function setTokenURIExtension(uint256 tokenId, string calldata uri) external;
            /**
             * @dev set the tokenURI of a token extension for multiple tokens.  Can only be called by extension that minted token.
             */
            function setTokenURIExtension(uint256[] memory tokenId, string[] calldata uri) external;
            /**
             * @dev set the baseTokenURI for tokens with no extension.  Can only be called by owner/admin.
             * For tokens with no uri configured, tokenURI will return "uri+tokenId"
             */
            function setBaseTokenURI(string calldata uri) external;
            /**
             * @dev set the common prefix for tokens with no extension.  Can only be called by owner/admin.
             * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
             * Useful if you want to use ipfs/arweave
             */
            function setTokenURIPrefix(string calldata prefix) external;
            /**
             * @dev set the tokenURI of a token with no extension.  Can only be called by owner/admin.
             */
            function setTokenURI(uint256 tokenId, string calldata uri) external;
            /**
             * @dev set the tokenURI of multiple tokens with no extension.  Can only be called by owner/admin.
             */
            function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external;
            /**
             * @dev set a permissions contract for an extension.  Used to control minting.
             */
            function setMintPermissions(address extension, address permissions) external;
            /**
             * @dev Configure so transfers of tokens created by the caller (must be extension) gets approval
             * from the extension before transferring
             */
            function setApproveTransferExtension(bool enabled) external;
            /**
             * @dev get the extension of a given token
             */
            function tokenExtension(uint256 tokenId) external view returns (address);
            /**
             * @dev Set default royalties
             */
            function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external;
            /**
             * @dev Set royalties of a token
             */
            function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
            /**
             * @dev Set royalties of an extension
             */
            function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
            /**
             * @dev Get royalites of a token.  Returns list of receivers and basisPoints
             */
            function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
            
            // Royalty support for various other standards
            function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory);
            function getFeeBps(uint256 tokenId) external view returns (uint[] memory);
            function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
            function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256);
            /**
             * @dev Set the default approve transfer contract location.
             */
            function setApproveTransfer(address extension) external; 
            /**
             * @dev Get the default approve transfer contract location.
             */
            function getApproveTransfer() external view returns (address);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "./ICreatorCore.sol";
        /**
         * @dev Core ERC721 creator interface
         */
        interface IERC721CreatorCore is ICreatorCore {
            /**
             * @dev mint a token with no extension. Can only be called by an admin.
             * Returns tokenId minted
             */
            function mintBase(address to) external returns (uint256);
            /**
             * @dev mint a token with no extension. Can only be called by an admin.
             * Returns tokenId minted
             */
            function mintBase(address to, string calldata uri) external returns (uint256);
            /**
             * @dev batch mint a token with no extension. Can only be called by an admin.
             * Returns tokenId minted
             */
            function mintBaseBatch(address to, uint16 count) external returns (uint256[] memory);
            /**
             * @dev batch mint a token with no extension. Can only be called by an admin.
             * Returns tokenId minted
             */
            function mintBaseBatch(address to, string[] calldata uris) external returns (uint256[] memory);
            /**
             * @dev mint a token. Can only be called by a registered extension.
             * Returns tokenId minted
             */
            function mintExtension(address to) external returns (uint256);
            /**
             * @dev mint a token. Can only be called by a registered extension.
             * Returns tokenId minted
             */
            function mintExtension(address to, string calldata uri) external returns (uint256);
            /**
             * @dev mint a token. Can only be called by a registered extension.
             * Returns tokenId minted
             */
            function mintExtension(address to, uint80 data) external returns (uint256);
            /**
             * @dev batch mint a token. Can only be called by a registered extension.
             * Returns tokenIds minted
             */
            function mintExtensionBatch(address to, uint16 count) external returns (uint256[] memory);
            /**
             * @dev batch mint a token. Can only be called by a registered extension.
             * Returns tokenId minted
             */
            function mintExtensionBatch(address to, string[] calldata uris) external returns (uint256[] memory);
            /**
             * @dev batch mint a token. Can only be called by a registered extension.
             * Returns tokenId minted
             */
            function mintExtensionBatch(address to, uint80[] calldata data) external returns (uint256[] memory);
            /**
             * @dev burn a token. Can only be called by token owner or approved address.
             * On burn, calls back to the registered extension's onBurn method
             */
            function burn(uint256 tokenId) external;
            /**
             * @dev get token data
             */
            function tokenData(uint256 tokenId) external view returns (uint80);
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@manifoldxyz/libraries-solidity/contracts/access/AdminControlUpgradeable.sol";
        import "./core/ERC721CreatorCore.sol";
        import "./token/ERC721/ERC721Upgradeable.sol";
        /**
         * @dev ERC721Creator implementation
         */
        contract ERC721CreatorImplementation is AdminControlUpgradeable, ERC721Upgradeable, ERC721CreatorCore {
            using EnumerableSet for EnumerableSet.AddressSet;
            /**
             * Initializer
             */
            function initialize(string memory _name, string memory _symbol) public initializer {
                __ERC721_init(_name, _symbol);
                __Ownable_init();
            }
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Core, ERC721CreatorCore, AdminControlUpgradeable) returns (bool) {
                return ERC721CreatorCore.supportsInterface(interfaceId) || ERC721Core.supportsInterface(interfaceId) || AdminControlUpgradeable.supportsInterface(interfaceId);
            }
            function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint96 data) internal virtual override {
                _approveTransfer(from, to, tokenId, uint16(data));
            }
            /**
             * @dev See {ICreatorCore-registerExtension}.
             */
            function registerExtension(address extension, string calldata baseURI) external override adminRequired {
                requireNonBlacklist(extension);
                _registerExtension(extension, baseURI, false);
            }
            /**
             * @dev See {ICreatorCore-registerExtension}.
             */
            function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external override adminRequired {
                requireNonBlacklist(extension);
                _registerExtension(extension, baseURI, baseURIIdentical);
            }
            /**
             * @dev See {ICreatorCore-unregisterExtension}.
             */
            function unregisterExtension(address extension) external override adminRequired {
                _unregisterExtension(extension);
            }
            /**
             * @dev See {ICreatorCore-blacklistExtension}.
             */
            function blacklistExtension(address extension) external override adminRequired {
                _blacklistExtension(extension);
            }
            /**
             * @dev See {ICreatorCore-setBaseTokenURIExtension}.
             */
            function setBaseTokenURIExtension(string calldata uri) external override {
                requireExtension();
                _setBaseTokenURIExtension(uri, false);
            }
            /**
             * @dev See {ICreatorCore-setBaseTokenURIExtension}.
             */
            function setBaseTokenURIExtension(string calldata uri, bool identical) external override {
                requireExtension();
                _setBaseTokenURIExtension(uri, identical);
            }
            /**
             * @dev See {ICreatorCore-setTokenURIPrefixExtension}.
             */
            function setTokenURIPrefixExtension(string calldata prefix) external override {
                requireExtension();
                _setTokenURIPrefixExtension(prefix);
            }
            /**
             * @dev See {ICreatorCore-setTokenURIExtension}.
             */
            function setTokenURIExtension(uint256 tokenId, string calldata uri) external override {
                requireExtension();
                _setTokenURIExtension(tokenId, uri);
            }
            /**
             * @dev See {ICreatorCore-setTokenURIExtension}.
             */
            function setTokenURIExtension(uint256[] calldata tokenIds, string[] calldata uris) external override {
                requireExtension();
                require(tokenIds.length == uris.length, "Invalid input");
                for (uint i; i < tokenIds.length;) {
                    _setTokenURIExtension(tokenIds[i], uris[i]);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev See {ICreatorCore-setBaseTokenURI}.
             */
            function setBaseTokenURI(string calldata uri) external override adminRequired {
                _setBaseTokenURI(uri);
            }
            /**
             * @dev See {ICreatorCore-setTokenURIPrefix}.
             */
            function setTokenURIPrefix(string calldata prefix) external override adminRequired {
                _setTokenURIPrefix(prefix);
            }
            /**
             * @dev See {ICreatorCore-setTokenURI}.
             */
            function setTokenURI(uint256 tokenId, string calldata uri) external override adminRequired {
                _setTokenURI(tokenId, uri);
            }
            /**
             * @dev See {ICreatorCore-setTokenURI}.
             */
            function setTokenURI(uint256[] calldata tokenIds, string[] calldata uris) external override adminRequired {
                require(tokenIds.length == uris.length, "Invalid input");
                for (uint i; i < tokenIds.length;) {
                    _setTokenURI(tokenIds[i], uris[i]);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev See {ICreatorCore-setMintPermissions}.
             */
            function setMintPermissions(address extension, address permissions) external override adminRequired {
                _setMintPermissions(extension, permissions);
            }
            /**
             * @dev See {IERC721CreatorCore-mintBase}.
             */
            function mintBase(address to) public virtual override nonReentrant adminRequired returns(uint256) {
                return _mintBase(to, "", 0);
            }
            /**
             * @dev See {IERC721CreatorCore-mintBase}.
             */
            function mintBase(address to, string calldata uri) public virtual override nonReentrant adminRequired returns(uint256) {
                return _mintBase(to, uri, 0);
            }
            /**
             * @dev See {IERC721CreatorCore-mintBaseBatch}.
             */
            function mintBaseBatch(address to, uint16 count) public virtual override nonReentrant adminRequired returns(uint256[] memory tokenIds) {
                tokenIds = new uint256[](count);
                uint256 firstTokenId = _tokenCount+1;
                _tokenCount += count;
                for (uint i; i < count;) {
                    tokenIds[i] = _mintBase(to, "", firstTokenId+i);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev See {IERC721CreatorCore-mintBaseBatch}.
             */
            function mintBaseBatch(address to, string[] calldata uris) public virtual override nonReentrant adminRequired returns(uint256[] memory tokenIds) {
                tokenIds = new uint256[](uris.length);
                uint256 firstTokenId = _tokenCount+1;
                _tokenCount += uris.length;
                for (uint i; i < uris.length;) {
                    tokenIds[i] = _mintBase(to, uris[i], firstTokenId+i);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev Mint token with no extension
             */
            function _mintBase(address to, string memory uri, uint256 tokenId) internal virtual returns(uint256) {
                if (tokenId == 0) {
                    ++_tokenCount;
                    tokenId = _tokenCount;
                }
                // Call pre mint
                _preMintBase(to, tokenId);
                _safeMint(to, tokenId, 0);
                if (bytes(uri).length > 0) {
                    _tokenURIs[tokenId] = uri;
                }
                return tokenId;
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtension}.
             */
            function mintExtension(address to) public virtual override nonReentrant returns(uint256) {
                requireExtension();
                return _mintExtension(to, "", 0, 0);
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtension}.
             */
            function mintExtension(address to, string calldata uri) public virtual override nonReentrant returns(uint256) {
                requireExtension();
                return _mintExtension(to, uri, 0, 0);
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtension}.
             */
            function mintExtension(address to, uint80 data) public virtual override nonReentrant returns(uint256) {
                requireExtension();
                return _mintExtension(to, "", data, 0);
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtensionBatch}.
             */
            function mintExtensionBatch(address to, uint16 count) public virtual override nonReentrant returns(uint256[] memory tokenIds) {
                requireExtension();
                tokenIds = new uint256[](count);
                uint256 firstTokenId = _tokenCount+1;
                _tokenCount += count;
                for (uint i; i < count;) {
                    tokenIds[i] = _mintExtension(to, "", 0, firstTokenId+i);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtensionBatch}.
             */
            function mintExtensionBatch(address to, string[] calldata uris) public virtual override nonReentrant returns(uint256[] memory tokenIds) {
                requireExtension();
                tokenIds = new uint256[](uris.length);
                uint256 firstTokenId = _tokenCount+1;
                _tokenCount += uris.length;
                for (uint i; i < uris.length;) {
                    tokenIds[i] = _mintExtension(to, uris[i], 0, firstTokenId+i);
                    unchecked { ++i; }
                }
            }
            /**
             * @dev See {IERC721CreatorCore-mintExtensionBatch}.
             */
            function mintExtensionBatch(address to, uint80[] calldata data) public virtual override nonReentrant returns(uint256[] memory tokenIds) {
                requireExtension();
                tokenIds = new uint256[](data.length);
                uint256 firstTokenId = _tokenCount+1;
                _tokenCount += data.length;
                for (uint i; i < data.length;) {
                    tokenIds[i] = _mintExtension(to, "", data[i], firstTokenId+i);
                    unchecked { ++i; }
                }
            }
            
            /**
             * @dev Mint token via extension
             */
            function _mintExtension(address to, string memory uri, uint80 data, uint256 tokenId) internal virtual returns(uint256) {
                if (tokenId == 0) {
                    ++_tokenCount;
                    tokenId = _tokenCount;
                }
                _checkMintPermissions(to, tokenId);
                // Call pre mint
                _preMintExtension(to, tokenId);
                _safeMint(to, tokenId, data << 16 | _extensionToIndex[msg.sender]);
                if (bytes(uri).length > 0) {
                    _tokenURIs[tokenId] = uri;
                }
                return tokenId;
            }
            /**
             * @dev See {IERC721CreatorCore-tokenExtension}.
             */
            function tokenExtension(uint256 tokenId) public view virtual override returns (address extension) {
                require(_exists(tokenId), "Nonexistent token");
                extension = _tokenExtension(tokenId);
                require(extension != address(0), "No extension for token");
                require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
            }
            /**
             * @dev See {IERC721CreatorCore-burn}.
             */
            function burn(uint256 tokenId) public virtual override nonReentrant {
                require(_isApprovedOrOwner(msg.sender, tokenId), "Caller is not owner or approved");
                address owner = ownerOf(tokenId);
                address extension = _tokenExtension(tokenId);
                _burn(tokenId);
                _postBurn(owner, tokenId, extension);
            }
            /**
             * @dev See {ICreatorCore-setRoyalties}.
             */
            function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                _setRoyaltiesExtension(address(0), receivers, basisPoints);
            }
            /**
             * @dev See {ICreatorCore-setRoyalties}.
             */
            function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                require(_exists(tokenId), "Nonexistent token");
                _setRoyalties(tokenId, receivers, basisPoints);
            }
            /**
             * @dev See {ICreatorCore-setRoyaltiesExtension}.
             */
            function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                _setRoyaltiesExtension(extension, receivers, basisPoints);
            }
            /**
             * @dev See {ICreatorCore-getRoyalties}.
             */
            function getRoyalties(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) {
                require(_exists(tokenId), "Nonexistent token");
                return _getRoyalties(tokenId);
            }
            /**
             * @dev See {ICreatorCore-getFees}.
             */
            function getFees(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) {
                require(_exists(tokenId), "Nonexistent token");
                return _getRoyalties(tokenId);
            }
            /**
             * @dev See {ICreatorCore-getFeeRecipients}.
             */
            function getFeeRecipients(uint256 tokenId) external view virtual override returns (address payable[] memory) {
                require(_exists(tokenId), "Nonexistent token");
                return _getRoyaltyReceivers(tokenId);
            }
            /**
             * @dev See {ICreatorCore-getFeeBps}.
             */
            function getFeeBps(uint256 tokenId) external view virtual override returns (uint[] memory) {
                require(_exists(tokenId), "Nonexistent token");
                return _getRoyaltyBPS(tokenId);
            }
            
            /**
             * @dev See {ICreatorCore-royaltyInfo}.
             */
            function royaltyInfo(uint256 tokenId, uint256 value) external view virtual override returns (address, uint256) {
                require(_exists(tokenId), "Nonexistent token");
                return _getRoyaltyInfo(tokenId, value);
            } 
            /**
             * @dev See {IERC721Metadata-tokenURI}.
             */
            function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                require(_exists(tokenId), "Nonexistent token");
                return _tokenURI(tokenId);
            }
            /**
             * @dev See {ICreatorCore-setApproveTransfer}.
             */
            function setApproveTransfer(address extension) external override adminRequired {
                _setApproveTransferBase(extension);
            }
            function _tokenExtension(uint256 tokenId) internal view override returns(address) {
                uint16 extensionIndex = uint16(_tokenData[tokenId].data);
                if (extensionIndex == 0) return address(0);
                return _indexToExtension[extensionIndex];
            }
            /**
             * @dev See {IERC721CreatorCore-tokenData}.
             */
            function tokenData(uint256 tokenId) external view returns (uint80) {
                return uint80(_tokenData[tokenId].data >> 16);
            }
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * Implement this if you want your extension to approve a transfer
         */
        interface IERC721CreatorExtensionApproveTransfer is IERC165 {
            /**
             * @dev Set whether or not the creator will check the extension for approval of token transfer
             */
            function setApproveTransfer(address creator, bool enabled) external;
            /**
             * @dev Called by creator contract to approve a transfer
             */
            function approveTransfer(address operator, address from, address to, uint256 tokenId) external returns (bool);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Your extension is required to implement this interface if it wishes
         * to receive the onBurn callback whenever a token the extension created is
         * burned
         */
        interface IERC721CreatorExtensionBurnable is IERC165 {
            /**
             * @dev callback handler for burn events
             */
            function onBurn(address owner, uint256 tokenId) external;
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Implement this if you want your extension to have overloadable royalties
         */
        interface ICreatorExtensionRoyalties is IERC165 {
            /**
             * Get the royalties for a given creator/tokenId
             */
            function getRoyalties(address creator, uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Implement this if you want your extension to have overloadable URI's
         */
        interface ICreatorExtensionTokenURI is IERC165 {
            /**
             * Get the uri for a given creator/tokenId
             */
            function tokenURI(address creator, uint256 tokenId) external view returns (string memory);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /// @author: manifold.xyz
        import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
        /**
         * @dev Required interface of an ERC721Creator compliant extension contracts.
         */
        interface IERC721CreatorMintPermissions is IERC165 {
            /**
             * @dev get approval to mint
             */
            function approveMint(address extension, address to, uint256 tokenId) external;
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
        import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
        import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
        import "@openzeppelin/contracts/utils/Address.sol";
        import "@openzeppelin/contracts/utils/Strings.sol";
        import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
        /**
         * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard
         */
        abstract contract ERC721Core is ERC165, IERC721, IERC721Metadata {
            using Address for address;
            using Strings for uint256;
            // Token name
            string internal _name;
            // Token symbol
            string internal _symbol;
            struct TokenData {
                address owner;
                uint96 data;
            }
            // Mapping from token ID to token data
            mapping(uint256 => TokenData) internal _tokenData;
            // Mapping owner address to token count
            mapping(address => uint256) private _balances;
            // Mapping from token ID to approved address
            mapping(uint256 => address) private _tokenApprovals;
            // Mapping from owner to operator approvals
            mapping(address => mapping(address => bool)) private _operatorApprovals;
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                return
                    interfaceId == type(IERC721).interfaceId ||
                    interfaceId == type(IERC721Metadata).interfaceId ||
                    super.supportsInterface(interfaceId);
            }
            /**
             * @dev See {IERC721-balanceOf}.
             */
            function balanceOf(address owner) public view virtual override returns (uint256) {
                require(owner != address(0), "ERC721: address zero is not a valid owner");
                return _balances[owner];
            }
            /**
             * @dev See {IERC721-ownerOf}.
             */
            function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                address owner = _tokenData[tokenId].owner;
                require(owner != address(0), "ERC721: invalid token ID");
                return owner;
            }
            /**
             * @dev See {IERC721Metadata-name}.
             */
            function name() public view virtual override returns (string memory) {
                return _name;
            }
            /**
             * @dev See {IERC721Metadata-symbol}.
             */
            function symbol() public view virtual override returns (string memory) {
                return _symbol;
            }
            /**
             * @dev See {IERC721-approve}.
             */
            function approve(address to, uint256 tokenId) public virtual override {
                address owner = ERC721Core.ownerOf(tokenId);
                require(to != owner, "ERC721: approval to current owner");
                require(
                    msg.sender == owner || isApprovedForAll(owner, msg.sender),
                    "ERC721: approve caller is not token owner or approved for all"
                );
                _approve(to, tokenId);
            }
            /**
             * @dev See {IERC721-getApproved}.
             */
            function getApproved(uint256 tokenId) public view virtual override returns (address) {
                _requireMinted(tokenId);
                return _tokenApprovals[tokenId];
            }
            /**
             * @dev See {IERC721-setApprovalForAll}.
             */
            function setApprovalForAll(address operator, bool approved) public virtual override {
                _setApprovalForAll(msg.sender, operator, approved);
            }
            /**
             * @dev See {IERC721-isApprovedForAll}.
             */
            function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                return _operatorApprovals[owner][operator];
            }
            /**
             * @dev See {IERC721-transferFrom}.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public virtual override {
                //solhint-disable-next-line max-line-length
                require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: caller is not token owner or approved");
                _transfer(from, to, tokenId);
            }
            /**
             * @dev See {IERC721-safeTransferFrom}.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public virtual override {
                safeTransferFrom(from, to, tokenId, "");
            }
            /**
             * @dev See {IERC721-safeTransferFrom}.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) public virtual override {
                require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: caller is not token owner or approved");
                _safeTransfer(from, to, tokenId, data);
            }
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
             * are aware of the ERC721 protocol to prevent tokens from being forever locked.
             *
             * `data` is additional data, it has no specified format and it is sent in call to `to`.
             *
             * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
             * implement alternative mechanisms to perform token transfer, such as signature-based.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function _safeTransfer(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) internal virtual {
                _transfer(from, to, tokenId);
                require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
            }
            /**
             * @dev Returns whether `tokenId` exists.
             *
             * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
             *
             * Tokens start existing when they are minted (`_mint`),
             * and stop existing when they are burned (`_burn`).
             */
            function _exists(uint256 tokenId) internal view virtual returns (bool) {
                return _tokenData[tokenId].owner != address(0);
            }
            /**
             * @dev Returns whether `spender` is allowed to manage `tokenId`.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
                address owner = ERC721Core.ownerOf(tokenId);
                return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
            }
            /**
             * @dev Safely mints `tokenId` and transfers it to `to`.
             *
             * Requirements:
             *
             * - `tokenId` must not exist.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function _safeMint(address to, uint256 tokenId, uint96 tokenData) internal virtual {
                _safeMint(to, tokenId, tokenData, "");
            }
            /**
             * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
             * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
             */
            function _safeMint(
                address to,
                uint256 tokenId,
                uint96 tokenData,
                bytes memory data
            ) internal virtual {
                require(to != address(0), "ERC721: mint to the zero address");
                require(!_exists(tokenId), "ERC721: token already minted");
                _beforeTokenTransfer(address(0), to, tokenId, tokenData);
                unchecked {
                    // Will not overflow unless all 2**256 token ids are minted to the same owner.
                    // Given that tokens are minted one by one, it is impossible in practice that
                    // this ever happens. Might change if we allow batch minting.
                    // The ERC fails to describe this case.
                    _balances[to] += 1;
                }
                _tokenData[tokenId] = TokenData({
                    owner: to,
                    data: tokenData
                });
                emit Transfer(address(0), to, tokenId);
                _afterTokenTransfer(address(0), to, tokenId, tokenData);
                require(
                    _checkOnERC721Received(address(0), to, tokenId, data),
                    "ERC721: transfer to non ERC721Receiver implementer"
                );
            }
            /**
             * @dev Destroys `tokenId`.
             * The approval is cleared when the token is burned.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits a {Transfer} event.
             */
            function _burn(uint256 tokenId) internal virtual {
                TokenData memory tokenData = _tokenData[tokenId];
                address owner = tokenData.owner;
                uint96 data = tokenData.data;
                _beforeTokenTransfer(owner, address(0), tokenId, data);
                // Clear approvals
                _approve(address(0), tokenId);
                unchecked {
                    // Cannot overflow, as that would require more tokens to be burned/transferred
                    // out than the owner initially received through minting and transferring in.
                    _balances[owner] -= 1;
                }
                delete _tokenData[tokenId];
                emit Transfer(owner, address(0), tokenId);
                _afterTokenTransfer(owner, address(0), tokenId, data);
            }
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             *
             * Emits a {Transfer} event.
             */
            function _transfer(
                address from,
                address to,
                uint256 tokenId
            ) internal virtual {
                TokenData memory tokenData = _tokenData[tokenId];
                address owner = tokenData.owner;
                require(owner == from, "ERC721: transfer from incorrect owner");
                require(to != address(0), "ERC721: transfer to the zero address");
                uint96 data = tokenData.data;
                _beforeTokenTransfer(from, to, tokenId, data);
                // Clear approvals from the previous owner
                _approve(address(0), tokenId);
                unchecked {
                    // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
                    // `from`'s balance is the number of token held, which is at least one before the current
                    // transfer.
                    // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
                    // all 2**256 token ids to be minted, which in practice is impossible.
                    _balances[from] -= 1;
                    _balances[to] += 1;
                }
                _tokenData[tokenId].owner = to;
                emit Transfer(from, to, tokenId);
                _afterTokenTransfer(from, to, tokenId, data);
            }
            /**
             * @dev Approve `to` to operate on `tokenId`
             *
             * Emits an {Approval} event.
             */
            function _approve(address to, uint256 tokenId) internal virtual {
                _tokenApprovals[tokenId] = to;
                emit Approval(ERC721Core.ownerOf(tokenId), to, tokenId);
            }
            /**
             * @dev Approve `operator` to operate on all of `owner` tokens
             *
             * Emits an {ApprovalForAll} event.
             */
            function _setApprovalForAll(
                address owner,
                address operator,
                bool approved
            ) internal virtual {
                require(owner != operator, "ERC721: approve to caller");
                _operatorApprovals[owner][operator] = approved;
                emit ApprovalForAll(owner, operator, approved);
            }
            /**
             * @dev Reverts if the `tokenId` has not been minted yet.
             */
            function _requireMinted(uint256 tokenId) internal view virtual {
                require(_exists(tokenId), "ERC721: invalid token ID");
            }
            /**
             * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
             * The call is not executed if the target address is not a contract.
             *
             * @param from address representing the previous owner of the given token ID
             * @param to target address that will receive the tokens
             * @param tokenId uint256 ID of the token to be transferred
             * @param data bytes optional data to send along with the call
             * @return bool whether the call correctly returned the expected magic value
             */
            function _checkOnERC721Received(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) private returns (bool) {
                if (to.isContract()) {
                    try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
                        return retval == IERC721Receiver.onERC721Received.selector;
                    } catch (bytes memory reason) {
                        if (reason.length == 0) {
                            revert("ERC721: transfer to non ERC721Receiver implementer");
                        } else {
                            /// @solidity memory-safe-assembly
                            assembly {
                                revert(add(32, reason), mload(reason))
                            }
                        }
                    }
                } else {
                    return true;
                }
            }
            /**
             * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
             * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
             * - When `from` is zero, the tokens will be minted for `to`.
             * - When `to` is zero, ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(
                address from,
                address to,
                uint256 tokenId,
                uint96 tokenData
            ) internal virtual {}
            /**
             * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
             * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
             * - When `from` is zero, the tokens were minted for `to`.
             * - When `to` is zero, ``from``'s tokens were burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _afterTokenTransfer(
                address from,
                address to,
                uint256 tokenId,
                uint96 tokenData
            ) internal virtual {}
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./ERC721Core.sol";
        import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
        /**
         * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard,
         */
        abstract contract ERC721Upgradeable is Initializable, ERC721Core {
            /// @custom:oz-upgrades-unsafe-allow constructor
            constructor() {
                _disableInitializers();
            }
            /**
             * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
             */
            function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {
                __ERC721_init_unchained(name_, symbol_);
            }
            function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
                _name = name_;
                _symbol = symbol_;
            }
        }
        

        File 5 of 5: PayableProxy
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.7;
        import { PayableProxyInterface } from "../interfaces/PayableProxyInterface.sol";
        interface IUpgradeBeacon {
            /**
             * @notice An external view function that returns the implementation.
             *
             * @return The address of the implementation.
             */
            function implementation() external view returns (address);
        }
        /**
         * @title   PayableProxy
         * @author  OpenSea Protocol Team
         * @notice  PayableProxy is a beacon proxy which will immediately return if
         *          called with callvalue. Otherwise, it will delegatecall the beacon
         *          implementation.
         */
        contract PayableProxy is PayableProxyInterface {
            // Address of the beacon.
            address private immutable _beacon;
            constructor(address beacon) payable {
                // Ensure the origin is an approved deployer.
                require(
                    (tx.origin == address(0x939C8d89EBC11fA45e576215E2353673AD0bA18A) ||
                        tx.origin ==
                        address(0xe80a65eB7a3018DedA407e621Ef5fb5B416678CA) ||
                        tx.origin ==
                        address(0x86D26897267711ea4b173C8C124a0A73612001da) ||
                        tx.origin ==
                        address(0x3B52ad533687Ce908bA0485ac177C5fb42972962)),
                    "Deployment must originate from an approved deployer."
                );
                // Set the initial beacon.
                _beacon = beacon;
            }
            function initialize(address ownerToSet) external {
                // Ensure the origin is an approved deployer.
                require(
                    (tx.origin == address(0x939C8d89EBC11fA45e576215E2353673AD0bA18A) ||
                        tx.origin ==
                        address(0xe80a65eB7a3018DedA407e621Ef5fb5B416678CA) ||
                        tx.origin ==
                        address(0x86D26897267711ea4b173C8C124a0A73612001da) ||
                        tx.origin ==
                        address(0x3B52ad533687Ce908bA0485ac177C5fb42972962)),
                    "Initialize must originate from an approved deployer."
                );
                // Get the implementation address from the provided beacon.
                address implementation = IUpgradeBeacon(_beacon).implementation();
                // Create the initializationCalldata from the provided parameters.
                bytes memory initializationCalldata = abi.encodeWithSignature(
                    "initialize(address)",
                    ownerToSet
                );
                // Delegatecall into the implementation, supplying initialization
                // calldata.
                (bool ok, ) = implementation.delegatecall(initializationCalldata);
                // Revert and include revert data if delegatecall to implementation
                // reverts.
                if (!ok) {
                    assembly {
                        returndatacopy(0, 0, returndatasize())
                        revert(0, returndatasize())
                    }
                }
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by
             *      `_implementation()`. Will run if no other function in the contract
             *      matches the call data.
             */
            fallback() external payable override {
                _fallback();
            }
            /**
             * @dev Internal fallback function that delegates calls to the address
             *      returned by `_implementation()`. Will run if no other function
             *      in the contract matches the call data.
             */
            function _fallback() internal {
                // Delegate if call value is zero.
                if (msg.value == 0) {
                    _delegate(_implementation());
                }
            }
            /**
             * @dev Delegates the current call to `implementation`.
             *
             * This function does not return to its internal call site, it will
             * return directly to the external caller.
             */
            function _delegate(address implementation) internal virtual {
                assembly {
                    // Copy msg.data. We take full control of memory in this
                    // inline assembly block because it will not return to
                    // Solidity code. We overwrite the Solidity scratch pad
                    // at memory position 0.
                    calldatacopy(0, 0, calldatasize())
                    // Call the implementation.
                    // out and outsize are 0 because we don't know the size yet.
                    let result := delegatecall(
                        gas(),
                        implementation,
                        0,
                        calldatasize(),
                        0,
                        0
                    )
                    // Copy the returned data.
                    returndatacopy(0, 0, returndatasize())
                    switch result
                    // delegatecall returns 0 on error.
                    case 0 {
                        revert(0, returndatasize())
                    }
                    default {
                        return(0, returndatasize())
                    }
                }
            }
            /**
             * @dev This function returns the address to which the fallback function
             *      should delegate.
             */
            function _implementation() internal view returns (address) {
                return IUpgradeBeacon(_beacon).implementation();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.7;
        /**
         * @title   PayableProxyInterface
         * @author  OpenSea Protocol Team
         * @notice  PayableProxyInterface contains all external function interfaces
         *          for the payable proxy.
         */
        interface PayableProxyInterface {
            /**
             * @dev Fallback function that delegates calls to the address returned by
             *      `_implementation()`. Will run if no other function in the contract
             *      matches the call data.
             */
            fallback() external payable;
        }