ETH Price: $3,035.25 (+1.31%)

Transaction Decoder

Block:
23899265 at Nov-28-2025 07:29:59 PM +UTC
Transaction Fee:
0.000424367777292744 ETH $1.29
Gas Used:
207,773 Gas / 2.042458728 Gwei

Emitted Events:

158 QuirkiesV2.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000020ec02894d748c59c01b6bf08fe283d7bb75a5d2, 0x000000000000000000000000629a768fa53168c1601832d410d667ff11f7df69, 0x0000000000000000000000000000000000000000000000000000000000000686 )
159 Seaport.OrderFulfilled( orderHash=ED6DDFAAEF6CAFE01A087936D0AE5AC6239BCBA1248709467268D14D6B22F3AC, offerer=0x20ec02894d748c59c01b6bf08fe283d7bb75a5d2, zone=SignedZone, recipient=[Sender] 0x629a768fa53168c1601832d410d667ff11f7df69, offer=, consideration= )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...1123eB395
(Seaport 1.6)
0x0000a26b...000fAa719
15.507830666880186978 Eth15.514060666880186978 Eth0.00623
0x20eC0289...7bB75A5d2 0.102461034167526375 Eth0.675621034167526375 Eth0.57316
0x34293C7F...71d3E3f26 7.252832836233014988 Eth7.296442836233014988 Eth0.04361
(Titan Builder)
13.54910414649172766 Eth13.54951969249172766 Eth0.000415546
0x629A768f...F11f7dF69
0.631299033845715112 Eth
Nonce: 28
0.007874666068422368 Eth
Nonce: 29
0.623424367777292744
0xD4B7D9bb...a983cCCB1

Execution Trace

ETH 0.623 Seaport.fulfillAdvancedOrder( [{name:parameters, type:tuple, order:1, indexed:false, value:[{name:offerer, type:address, order:1, indexed:false, value:0x20eC02894D748C59c01B6bF08FE283D7bB75A5d2, valueString:0x20eC02894D748C59c01B6bF08FE283D7bB75A5d2}, {name:zone, type:address, order:2, indexed:false, value:0x000056F7000000EcE9003ca63978907a00FFD100, valueString:0x000056F7000000EcE9003ca63978907a00FFD100}, {name:offer, type:tuple[], order:3, indexed:false}, {name:consideration, type:tuple[], order:4, indexed:false}, {name:orderType, type:uint8, order:5, indexed:false, value:2, valueString:2}, {name:startTime, type:uint256, order:6, indexed:false, value:1763997377, valueString:1763997377}, {name:endTime, type:uint256, order:7, indexed:false, value:1779549377, valueString:1779549377}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:27855337018906766782546881864045825683096516384821792734235480334695368433293, valueString:27855337018906766782546881864045825683096516384821792734235480334695368433293}, {name:conduitKey, type:bytes32, order:10, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalConsiderationItems, type:uint256, order:11, indexed:false, value:3, valueString:3}], valueString:[{name:offerer, type:address, order:1, indexed:false, value:0x20eC02894D748C59c01B6bF08FE283D7bB75A5d2, valueString:0x20eC02894D748C59c01B6bF08FE283D7bB75A5d2}, {name:zone, type:address, order:2, indexed:false, value:0x000056F7000000EcE9003ca63978907a00FFD100, valueString:0x000056F7000000EcE9003ca63978907a00FFD100}, {name:offer, type:tuple[], order:3, indexed:false}, {name:consideration, type:tuple[], order:4, indexed:false}, {name:orderType, type:uint8, order:5, indexed:false, value:2, valueString:2}, {name:startTime, type:uint256, order:6, indexed:false, value:1763997377, valueString:1763997377}, {name:endTime, type:uint256, order:7, indexed:false, value:1779549377, valueString:1779549377}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:27855337018906766782546881864045825683096516384821792734235480334695368433293, valueString:27855337018906766782546881864045825683096516384821792734235480334695368433293}, {name:conduitKey, type:bytes32, order:10, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalConsiderationItems, type:uint256, order:11, indexed:false, value:3, valueString:3}]}, {name:numerator, type:uint120, order:2, indexed:false, value:1, valueString:1}, {name:denominator, type:uint120, order:3, indexed:false, value:1, valueString:1}, {name:signature, type:bytes, order:4, indexed:false, value:0xECD00D42E0C27E657D1FD569D6039807DBE3DFE52A172722152A152433F829EC66CBECB4241305A2AAD9F06A14EEBA9300C95A2CC6ACF33189429FBFE60BD50800000164207D745B4C0FAB5C0231B39DA159157686F4026C1DC2858B64BDDFBC4DE037, valueString:0xECD00D42E0C27E657D1FD569D6039807DBE3DFE52A172722152A152433F829EC66CBECB4241305A2AAD9F06A14EEBA9300C95A2CC6ACF33189429FBFE60BD50800000164207D745B4C0FAB5C0231B39DA159157686F4026C1DC2858B64BDDFBC4DE037}, {name:extraData, type:bytes, order:5, indexed:false, value:0x00629A768FA53168C1601832D410D667FF11F7DF69000000006929F95B1A911D153331E049307CB946BF9124E18A2976A8F7ADBBA5ECBB1873B86A8720730AC0F6E6595D830BDF1C7A9CDA4C611E018EDA463CCE93F3DDDDB59EFE8831080000000000000000000000000000000000000000000000000000000000000000A000027A9B2802E1DDF7000061001E5C005A0000, valueString:0x00629A768FA53168C1601832D410D667FF11F7DF69000000006929F95B1A911D153331E049307CB946BF9124E18A2976A8F7ADBBA5ECBB1873B86A8720730AC0F6E6595D830BDF1C7A9CDA4C611E018EDA463CCE93F3DDDDB59EFE8831080000000000000000000000000000000000000000000000000000000000000000A000027A9B2802E1DDF7000061001E5C005A0000}], , fulfillerConduitKey=0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, recipient=0x629A768fa53168C1601832D410d667fF11f7dF69 ) => ( fulfilled=True )
  • Null: 0x000...001.01a46207( )
  • Null: 0x000...004.00000000( )
  • Null: 0x000...004.00000000( )
  • Null: 0x000...004.00000000( )
  • Null: 0x000...004.00000000( )
  • Null: 0x000...004.00000000( )
  • SignedZone.authorizeOrder( )
    • Null: 0x000...001.060130b2( )
    • StrictAuthorizedTransferSecurityRegistry.beforeAuthorizedTransfer( token=0xD4B7D9bb20fA20dDADa9eCEf8a7355ca983cCCB1, tokenId=1670 )
    • ETH 0.57316 0x20ec02894d748c59c01b6bf08fe283d7bb75a5d2.CALL( )
    • ETH 0.00623 PayableProxy.CALL( )
    • ETH 0.04361 0x34293c7fcf17d1cb8657bd2f2a5592471d3e3f26.CALL( )
    • OpenSea: Conduit.4ce34aa2( )
      • QuirkiesV2.23b872dd( )
        • 0x0cce03372b05cd40b133f782e0e1c327a08bf28b.23b872dd( )
          • StrictAuthorizedTransferSecurityRegistry.applyCollectionTransferPolicy( caller=0x1E0049783F008A0085193E00003D00cd54003c71, from=0x20eC02894D748C59c01B6bF08FE283D7bB75A5d2, to=0x629A768fa53168C1601832D410d667fF11f7dF69 )
          • Null: 0x000...004.ed6ddfaa( )
          • SignedZone.validateOrder( )
            • StrictAuthorizedTransferSecurityRegistry.afterAuthorizedTransfer( token=0xD4B7D9bb20fA20dDADa9eCEf8a7355ca983cCCB1, tokenId=1670 )
              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: QuirkiesV2
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
               * proxy whose upgrades are fully controlled by the current implementation.
               */
              interface IERC1822Proxiable {
                  /**
                   * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                   * address.
                   *
                   * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                   * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                   * function revert if invoked through a proxy.
                   */
                  function proxiableUUID() external view returns (bytes32);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
              pragma solidity ^0.8.0;
              import "../Proxy.sol";
              import "./ERC1967Upgrade.sol";
              /**
               * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
               * implementation address that can be changed. This address is stored in storage in the location specified by
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
               * implementation behind the proxy.
               */
              contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                  /**
                   * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                   *
                   * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                   * function call, and allows initializing the storage of the proxy like a Solidity constructor.
                   */
                  constructor(address _logic, bytes memory _data) payable {
                      _upgradeToAndCall(_logic, _data, false);
                  }
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function _implementation() internal view virtual override returns (address impl) {
                      return ERC1967Upgrade._getImplementation();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
              pragma solidity ^0.8.2;
              import "../beacon/IBeacon.sol";
              import "../../interfaces/draft-IERC1822.sol";
              import "../../utils/Address.sol";
              import "../../utils/StorageSlot.sol";
              /**
               * @dev This abstract contract provides getters and event emitting update functions for
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
               *
               * _Available since v4.1._
               *
               * @custom:oz-upgrades-unsafe-allow delegatecall
               */
              abstract contract ERC1967Upgrade {
                  // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                  bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                  /**
                   * @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 Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function _getImplementation() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the EIP1967 implementation slot.
                   */
                  function _setImplementation(address newImplementation) private {
                      require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                      StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                  }
                  /**
                   * @dev Perform implementation upgrade
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeTo(address newImplementation) internal {
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                  }
                  /**
                   * @dev Perform implementation upgrade with additional setup call.
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeToAndCall(
                      address newImplementation,
                      bytes memory data,
                      bool forceCall
                  ) internal {
                      _upgradeTo(newImplementation);
                      if (data.length > 0 || forceCall) {
                          Address.functionDelegateCall(newImplementation, data);
                      }
                  }
                  /**
                   * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeToAndCallUUPS(
                      address newImplementation,
                      bytes memory data,
                      bool forceCall
                  ) internal {
                      // Upgrades from old implementations will perform a rollback test. This test requires the new
                      // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                      // this special case will break upgrade paths from old UUPS implementation to new ones.
                      if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                          _setImplementation(newImplementation);
                      } else {
                          try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                              require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                          } catch {
                              revert("ERC1967Upgrade: new implementation is not UUPS");
                          }
                          _upgradeToAndCall(newImplementation, data, forceCall);
                      }
                  }
                  /**
                   * @dev Storage slot with the admin of the contract.
                   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                   * validated in the constructor.
                   */
                  bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Returns the current admin.
                   */
                  function _getAdmin() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the EIP1967 admin slot.
                   */
                  function _setAdmin(address newAdmin) private {
                      require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                      StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                  }
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {AdminChanged} event.
                   */
                  function _changeAdmin(address newAdmin) internal {
                      emit AdminChanged(_getAdmin(), newAdmin);
                      _setAdmin(newAdmin);
                  }
                  /**
                   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                   * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                   */
                  bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                  /**
                   * @dev Emitted when the beacon is upgraded.
                   */
                  event BeaconUpgraded(address indexed beacon);
                  /**
                   * @dev Returns the current beacon.
                   */
                  function _getBeacon() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                  }
                  /**
                   * @dev Stores a new beacon in the EIP1967 beacon slot.
                   */
                  function _setBeacon(address newBeacon) private {
                      require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                      require(
                          Address.isContract(IBeacon(newBeacon).implementation()),
                          "ERC1967: beacon implementation is not a contract"
                      );
                      StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                  }
                  /**
                   * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                   * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                   *
                   * Emits a {BeaconUpgraded} event.
                   */
                  function _upgradeBeaconToAndCall(
                      address newBeacon,
                      bytes memory data,
                      bool forceCall
                  ) internal {
                      _setBeacon(newBeacon);
                      emit BeaconUpgraded(newBeacon);
                      if (data.length > 0 || forceCall) {
                          Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                      }
                  }
              }
              // 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 v4.4.1 (proxy/beacon/IBeacon.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev This is the interface that {BeaconProxy} expects of its beacon.
               */
              interface IBeacon {
                  /**
                   * @dev Must return an address that can be used as a delegate call target.
                   *
                   * {BeaconProxy} will check that this address is a contract.
                   */
                  function implementation() external view returns (address);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
              pragma solidity ^0.8.0;
              import "../ERC1967/ERC1967Proxy.sol";
              /**
               * @dev This contract implements a proxy that is upgradeable by an admin.
               *
               * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
               * clashing], which can potentially be used in an attack, this contract uses the
               * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
               * things that go hand in hand:
               *
               * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
               * that call matches one of the admin functions exposed by the proxy itself.
               * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
               * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
               * "admin cannot fallback to proxy target".
               *
               * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
               * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
               * to sudden errors when trying to call a function from the proxy implementation.
               *
               * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
               * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
               */
              contract TransparentUpgradeableProxy is ERC1967Proxy {
                  /**
                   * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                   * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                   */
                  constructor(
                      address _logic,
                      address admin_,
                      bytes memory _data
                  ) payable ERC1967Proxy(_logic, _data) {
                      _changeAdmin(admin_);
                  }
                  /**
                   * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                   */
                  modifier ifAdmin() {
                      if (msg.sender == _getAdmin()) {
                          _;
                      } else {
                          _fallback();
                      }
                  }
                  /**
                   * @dev Returns the current admin.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                   * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                   */
                  function admin() external ifAdmin returns (address admin_) {
                      admin_ = _getAdmin();
                  }
                  /**
                   * @dev Returns the current implementation.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                   * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                   */
                  function implementation() external ifAdmin returns (address implementation_) {
                      implementation_ = _implementation();
                  }
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {AdminChanged} event.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                   */
                  function changeAdmin(address newAdmin) external virtual ifAdmin {
                      _changeAdmin(newAdmin);
                  }
                  /**
                   * @dev Upgrade the implementation of the proxy.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                   */
                  function upgradeTo(address newImplementation) external ifAdmin {
                      _upgradeToAndCall(newImplementation, bytes(""), false);
                  }
                  /**
                   * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                   * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                   * proxied contract.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                   */
                  function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                      _upgradeToAndCall(newImplementation, data, true);
                  }
                  /**
                   * @dev Returns the current admin.
                   */
                  function _admin() internal view virtual returns (address) {
                      return _getAdmin();
                  }
                  /**
                   * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                   */
                  function _beforeFallback() internal virtual override {
                      require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                      super._beforeFallback();
                  }
              }
              // 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 (last updated v4.7.0) (utils/StorageSlot.sol)
              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:
               * ```
               * 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`, and `uint256`._
               */
              library StorageSlot {
                  struct AddressSlot {
                      address value;
                  }
                  struct BooleanSlot {
                      bool value;
                  }
                  struct Bytes32Slot {
                      bytes32 value;
                  }
                  struct Uint256Slot {
                      uint256 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
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.17;
              import {TransparentUpgradeableProxy} from "openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol";
              contract QuirkiesV2 is TransparentUpgradeableProxy {
                  constructor(
                      address logic_,
                      address admin_,
                      bytes memory data_
                  ) TransparentUpgradeableProxy(logic_, admin_, data_) {}
              }
              

              File 3 of 5: SignedZone
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              import {
                  ZoneParameters,
                  Schema
              } from "../../../../types/lib/ConsiderationStructs.sol";
              import { ZoneInterface } from "../../../interfaces/ZoneInterface.sol";
              import {
                  SignedZoneEventsAndErrors
              } from "../interfaces/SignedZoneEventsAndErrors.sol";
              import { SIP5Interface } from "../../interfaces/SIP5Interface.sol";
              import {
                  SignedZoneControllerInterface
              } from "../interfaces/SignedZoneControllerInterface.sol";
              import {
                  IAuthorizedTransferSecurityRegistry
              } from "lib/erc721c-seaport/src/interfaces/IAuthorizedTransferSecurityRegistry.sol";
              import "./lib/SignedZoneConstants.sol";
              /**
               * @title  SignedZone
               * @author ryanio, BCLeFevre
               * @notice SignedZone is an implementation of SIP-7 that requires orders
               *         to be signed by an approved signer.
               *         https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
               */
              contract SignedZone is SignedZoneEventsAndErrors, ZoneInterface, SIP5Interface {
                  /// @dev The zone's controller that is set during deployment.
                  address private immutable _controller;
                  /// @dev The authorized signers, and if they are active.
                  mapping(address => bool) private _signers;
                  /// @dev The EIP-712 digest parameters.
                  bytes32 internal immutable _NAME_HASH;
                  bytes32 internal immutable _VERSION_HASH = keccak256(bytes("2.0"));
                  // prettier-ignore
                  bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH = keccak256(
                        abi.encodePacked(
                          "EIP712Domain(",
                              "string name,",
                              "string version,",
                              "uint256 chainId,",
                              "address verifyingContract",
                          ")"
                        )
                      );
                  // prettier-ignore
                  bytes32 internal immutable _SIGNED_ORDER_TYPEHASH = keccak256(
                        abi.encodePacked(
                          "SignedOrder(",
                              "address fulfiller,",
                              "uint64 expiration,",
                              "bytes32 orderHash,",
                              "bytes context",
                          ")"
                        )
                      );
                  uint256 internal immutable _CHAIN_ID = block.chainid;
                  bytes32 internal immutable _DOMAIN_SEPARATOR;
                  address private immutable SEAPORT =
                      0x0000000000000068F116a894984e2DB1123eB395;
                  /**
                   * @notice Constructor to deploy the contract.
                   *
                   * @param zoneName The name for the zone used in the domain separator
                   *                 derivation.
                   */
                  constructor(string memory zoneName) {
                      // Set the deployer as the controller.
                      _controller = msg.sender;
                      // Set the name hash.
                      _NAME_HASH = keccak256(bytes(zoneName));
                      // Derive and set the domain separator.
                      _DOMAIN_SEPARATOR = _deriveDomainSeparator();
                      // Emit an event to signal a SIP-5 contract has been deployed.
                      emit SeaportCompatibleContractDeployed();
                  }
                  /**
                   * @notice The fallback function is used as a dispatcher for the
                   *         `updateSigner`, `isActiveSigner`, `getActiveSigners` and
                   *         `supportsInterface` functions.
                   */
                  // prettier-ignore
                  fallback(bytes calldata) external returns (bytes memory output) {
                      // Get the function selector.
                      bytes4 selector = msg.sig;
                      if (selector == UPDATE_SIGNER_SELECTOR) {
                          // abi.encodeWithSignature("updateSigner(address,bool)", signer,
                          // active)
                        
                          // Get the signer, and active status.
                          address signer = abi.decode(msg.data[4:], (address));
                          bool active = abi.decode(msg.data[36:], (bool));
                          // Call to update the signer.
                          _updateSigner(signer, active);
                      } else if (selector == GET_ACTIVE_SIGNERS_SELECTOR) {
                          // abi.encodeWithSignature("getActiveSigners()")
                      
                          // Call the internal function to get the active signers.
                          return abi.encode(_getActiveSigners());
                      } else if (selector == IS_ACTIVE_SIGNER_SELECTOR) {
                          // abi.encodeWithSignature("isActiveSigner(address)", signer)
                          // Get the signer.
                          address signer = abi.decode(msg.data[4:], (address));
                          // Call the internal function to determine if the signer is active.
                          return abi.encode(_isActiveSigner(signer));
                      }
                      else {
                           // Revert if the function selector is not supported.
                          assembly {
                              // Store left-padded selector with push4 (reduces bytecode),
                              // mem[28:32] = selector
                              mstore(0, UnsupportedFunctionSelector_error_selector)
                              // revert(abi.encodeWithSignature(
                              //  "UnsupportedFunctionSelector()"
                              // ))
                              revert(0x1c, UnsupportedFunctionSelector_error_length)
                          }
                      }
                  }
                  /**
                   * @notice Check if a given order including extraData is currently valid.
                   *
                   * @dev This function is called by Seaport whenever any extraData is
                   *      provided by the caller.
                   *
                   * @return authorizedOrderMagicValue A magic value indicating if the order
                   *                                   is currently valid.
                   */
                  function authorizeOrder(
                      ZoneParameters calldata zoneParameters
                  ) external override returns (bytes4 authorizedOrderMagicValue) {
                      if (msg.sender != SEAPORT) {
                          // Revert if the caller is not Seaport.
                          revert CallerNotSeaport();
                      }
                      // Check Zone Parameters validity.
                      _assertValidZoneParameters();
                      // Put the extraData and orderHash on the stack for cheaper access.
                      bytes calldata extraData = zoneParameters.extraData;
                      bytes32 orderHash = zoneParameters.orderHash;
                      // Declare a variable to hold the expiration.
                      uint64 expiration;
                      // Declare a variable to hold the substandard version byte.
                      uint256 subStandardVersionByte;
                      // Validate the extraData.
                      assembly {
                          // Get the length of the extraData.
                          let extraDataPtr := add(0x24, calldataload(Zone_extraData_cdPtr))
                          let extraDataLength := calldataload(extraDataPtr)
                          // Validate the extra data length.
                          if lt(
                              extraDataLength,
                              InvalidExtraDataLength_expected_length_substandard_1
                          ) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidExtraDataLength_error_selector)
                              mstore(InvalidExtraDataLength_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //   "InvalidExtraDataLength(bytes32)", orderHash)
                              // )
                              revert(0x1c, InvalidExtraDataLength_error_length)
                          }
                          // extraData bytes 0-1: SIP-6 version byte (MUST be 0x00)
                          let versionByte := shr(248, calldataload(add(extraDataPtr, 0x20)))
                          // Validate the SIP6 Version byte.
                          if iszero(eq(versionByte, 0x00)) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidSIP6Version_error_selector)
                              mstore(InvalidSIP6Version_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //   "InvalidSIP6Version(bytes32)", orderHash)
                              // )
                              revert(0x1c, InvalidSIP6Version_error_length)
                          }
                          // extraData bytes 93-94: Substandard #1
                          // (MUST be 0x00, 0x01, 0x07, 0x08, or 0x09)
                          subStandardVersionByte := shr(
                              248,
                              calldataload(
                                  add(extraDataPtr, ExtraData_substandard_version_byte_offset)
                              )
                          )
                          // Validate the substandard version byte.
                          if or(
                              gt(subStandardVersionByte, 0x09),
                              and(
                                  gt(subStandardVersionByte, 0x01),
                                  lt(subStandardVersionByte, 0x07)
                              )
                          ) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidSubstandardVersion_error_selector)
                              mstore(InvalidSubstandardVersion_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //   "InvalidSubstandardVersion(bytes32)", orderHash)
                              // )
                              revert(0x1c, InvalidSubstandardVersion_error_length)
                          }
                          // extraData bytes 21-29: expiration timestamp (uint64)
                          expiration := shr(
                              192,
                              calldataload(add(extraDataPtr, ExtraData_expiration_offset))
                          )
                          // Revert if expired.
                          if lt(expiration, timestamp()) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, SignatureExpired_error_selector)
                              mstore(SignatureExpired_error_expiration_ptr, expiration)
                              mstore(SignatureExpired_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //   "SignatureExpired(uint256,bytes32)", expiration, orderHash)
                              // )
                              revert(0x1c, SignatureExpired_error_length)
                          }
                          // Get the length of the consideration array.
                          let considerationLength := calldataload(
                              add(0x24, calldataload(Zone_consideration_head_cdPtr))
                          )
                          // Revert if the order does not have any consideration items due to
                          // the Substandard #1 requirement.
                          if iszero(considerationLength) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidSubstandardSupport_error_selector)
                              mstore(InvalidSubstandardSupport_error_reason_offset_ptr, 0x60)
                              mstore(
                                  InvalidSubstandardSupport_error_substandard_version_ptr,
                                  1
                              )
                              mstore(InvalidSubstandardSupport_error_orderHash_ptr, orderHash)
                              mstore(InvalidSubstandardSupport_error_reason_length_ptr, 0x2a)
                              mstore(
                                  InvalidSubstandardSupport_error_reason_ptr,
                                  "Consideration must have at least"
                              )
                              mstore(
                                  InvalidSubstandardSupport_error_reason_2_ptr,
                                  " one item."
                              )
                              // revert(abi.encodeWithSignature(
                              //     "InvalidSubstandardSupport(string,uint256,bytes32)",
                              //     reason,
                              //     substandardVersion,
                              //     orderHash
                              // ))
                              revert(0x1c, InvalidSubstandardSupport_error_length)
                          }
                      }
                      // Check the validity of the Substandard #1 extraData and get the
                      // expected fulfiller address.
                      address expectedFulfiller = (
                          _assertValidSubstandardAndGetExpectedFulfiller(orderHash)
                      );
                      // extraData bytes 29-93: signature
                      // (strictly requires 64 byte compact sig, EIP-2098)
                      bytes calldata signature = extraData[29:93];
                      // extraData bytes 93-126: context (fixed length, 32 bytes + 1 byte)
                      bytes calldata context;
                      if (subStandardVersionByte < 2) {
                          context = extraData[93:126];
                      } else if (subStandardVersionByte == 7) {
                          if (extraData.length < 166) {
                              assembly {
                                  // Store left-padded selector with push4, mem[28:32] = selector
                                  mstore(0, InvalidExtraDataLength_error_selector)
                                  mstore(
                                      InvalidExtraDataLength_error_orderHash_ptr,
                                      orderHash
                                  )
                                  // revert(abi.encodeWithSignature(
                                  //   "InvalidExtraDataLength(bytes32)", orderHash)
                                  // )
                                  revert(0x1c, InvalidExtraDataLength_error_length)
                              }
                          }
                          context = extraData[93:166];
                      } else {
                          if (extraData.length < 146) {
                              assembly {
                                  // Store left-padded selector with push4, mem[28:32] = selector
                                  mstore(0, InvalidExtraDataLength_error_selector)
                                  mstore(
                                      InvalidExtraDataLength_error_orderHash_ptr,
                                      orderHash
                                  )
                                  // revert(abi.encodeWithSignature(
                                  //   "InvalidExtraDataLength(bytes32)", orderHash)
                                  // )
                                  revert(0x1c, InvalidExtraDataLength_error_length)
                              }
                          }
                          context = extraData[93:146];
                      }
                      // Derive the signedOrder hash.
                      bytes32 signedOrderHash = _deriveSignedOrderHash(
                          expectedFulfiller,
                          expiration,
                          orderHash,
                          context
                      );
                      // Derive the EIP-712 digest using the domain separator and signedOrder
                      // hash.
                      bytes32 digest = _deriveEIP712Digest(
                          _domainSeparator(),
                          signedOrderHash
                      );
                      // Recover the signer address from the digest and signature.
                      address recoveredSigner = _recoverSigner(digest, signature);
                      // Revert if the signer is not active.
                      if (!_signers[recoveredSigner]) {
                          revert SignerNotActive(recoveredSigner, orderHash);
                      }
                      // Set the transfer status of the tokens to true.
                      _setTransferStatus(zoneParameters, true);
                      // Return the selector of authorizeOrder as the magic value.
                      authorizedOrderMagicValue = ZoneInterface.authorizeOrder.selector;
                  }
                  /**
                   * @notice Check if a given order including extraData is currently valid.
                   *
                   * @dev This function is called by Seaport whenever any extraData is
                   *      provided by the caller.
                   *
                   * @return validOrderMagicValue A magic value indicating if the order is
                   *                              currently valid.
                   */
                  function validateOrder(
                      ZoneParameters calldata zoneParameters
                  ) external override returns (bytes4 validOrderMagicValue) {
                      if (msg.sender != SEAPORT) {
                          // Revert if the caller is not Seaport.
                          revert CallerNotSeaport();
                      }
                      // Set the transfer status of the tokens to false.
                      _setTransferStatus(zoneParameters, false);
                      // Return the selector of validateOrder as the magic value.
                      validOrderMagicValue = ZoneInterface.validateOrder.selector;
                  }
                  /**
                   * @dev Returns Seaport metadata for this contract, returning the
                   *      contract name and supported schemas.
                   *
                   * @return name     The contract name
                   * @return schemas  The supported SIPs
                   */
                  function getSeaportMetadata()
                      external
                      view
                      override(SIP5Interface, ZoneInterface)
                      returns (string memory name, Schema[] memory schemas)
                  {
                      // Return the supported SIPs.
                      schemas = new Schema[](1);
                      schemas[0].id = 7;
                      // Get the SIP-7 information.
                      (
                          bytes32 domainSeparator,
                          string memory zoneName,
                          string memory apiEndpoint,
                          uint256[] memory substandards,
                          string memory documentationURI
                      ) = _sip7Information();
                      // Return the zone name.
                      name = zoneName;
                      // Encode the SIP-7 information.
                      schemas[0].metadata = abi.encode(
                          domainSeparator,
                          apiEndpoint,
                          substandards,
                          documentationURI
                      );
                  }
                  /**
                   * @dev Returns if the zone supports the interfaceId.
                   *
                   * @param interfaceId The interface identifier, as specified in ERC-165.
                   *
                   * @return supportsInterface True if the zone supports interfaceId, false
                   */
                  function supportsInterface(
                      bytes4 interfaceId
                  ) external view override returns (bool) {
                      // Call the internal function to determine if the interface is supported.
                      return _supportsInterface(interfaceId);
                  }
                  /**
                   * @dev Sets the transfer status of the token based on the consideration
                   *      items or offer items.
                   *
                   * @param zoneParameters The zone parameters.
                   * @param active The transfer status of the token.
                   */
                  function _setTransferStatus(
                      ZoneParameters calldata zoneParameters,
                      bool active
                  ) internal {
                      uint8 subStandardVersionByte = uint8(
                          bytes1(zoneParameters.extraData[93])
                      );
                      if (subStandardVersionByte < 2) {
                          return;
                      }
                      address registry = address(bytes20(zoneParameters.extraData[126:146]));
                      address token;
                      uint256 identifier;
                      uint256 amount;
                      if (uint256(zoneParameters.consideration[0].itemType) > 1) {
                          // Call on first consideration
                          token = zoneParameters.consideration[0].token;
                          identifier = zoneParameters.consideration[0].identifier;
                          amount = zoneParameters.consideration[0].amount;
                      } else {
                          // Call on first offer
                          token = zoneParameters.offer[0].token;
                          identifier = zoneParameters.offer[0].identifier;
                          amount = zoneParameters.offer[0].amount;
                      }
                      if (subStandardVersionByte == 7) {
                          address operator = address(
                              bytes20(zoneParameters.extraData[146:166])
                          );
                          if (active) {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .beforeAuthorizedTransfer(operator, token);
                          } else {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .afterAuthorizedTransfer(token);
                          }
                      } else if (subStandardVersionByte == 8) {
                          if (active) {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .beforeAuthorizedTransfer(token, identifier);
                          } else {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .afterAuthorizedTransfer(token, identifier);
                          }
                      }
                      /* subStandardVersionByte == 9 */
                      else {
                          if (active) {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .beforeAuthorizedTransferWithAmount(
                                      token,
                                      identifier,
                                      amount
                                  );
                          } else {
                              IAuthorizedTransferSecurityRegistry(registry)
                                  .afterAuthorizedTransferWithAmount(token, identifier);
                          }
                      }
                  }
                  /**
                   * @notice Add or remove a signer to the zone.
                   *         Only the controller can call this function.
                   *
                   * @param signer The signer address to add or remove.
                   */
                  function _updateSigner(address signer, bool active) internal {
                      // Only the controller can call this function.
                      _assertCallerIsController();
                      // Add or remove the signer.
                      active ? _addSigner(signer) : _removeSigner(signer);
                  }
                  /**
                   * @notice Add a new signer to the zone.
                   *         Only the controller or an active signer can call this function.
                   *
                   * @param signer The new signer address to add.
                   */
                  function _addSigner(address signer) internal {
                      // Set the signer's active status to true.
                      _signers[signer] = true;
                      // Emit an event that the signer was added.
                      emit SignerAdded(signer);
                  }
                  /**
                   * @notice Remove an active signer from the zone.
                   *         Only the controller or an active signer can call this function.
                   *
                   * @param signer The signer address to remove.
                   */
                  function _removeSigner(address signer) internal {
                      // Set the signer's active status to false.
                      _signers[signer] = false;
                      // Emit an event that the signer was removed.
                      emit SignerRemoved(signer);
                  }
                  /**
                   * @notice Returns the active signers for the zone. Note that the array of
                   *         active signers could grow to a size that this function could not
                   *         return, the array of active signers is  expected to be small,
                   *         and is managed by the controller.
                   *
                   * @return signers The active signers.
                   */
                  function _getActiveSigners()
                      internal
                      view
                      returns (address[] memory signers)
                  {
                      // Return the active signers for the zone by calling the controller.
                      signers = SignedZoneControllerInterface(_controller).getActiveSigners(
                          address(this)
                      );
                  }
                  /**
                   * @notice Returns if the given address is an active signer for the zone.
                   *
                   * @param signer The address to check if it is an active signer.
                   *
                   * @return The address is an active signer, false otherwise.
                   */
                  function _isActiveSigner(address signer) internal view returns (bool) {
                      // Return the active status of the caller.
                      return _signers[signer];
                  }
                  /**
                   * @notice Returns whether the interface is supported.
                   *
                   * @param interfaceId The interface id to check against.
                   */
                  function _supportsInterface(
                      bytes4 interfaceId
                  ) internal pure returns (bool) {
                      // Determine if the interface is supported.
                      return (interfaceId == type(SIP5Interface).interfaceId || // SIP-5
                          interfaceId == type(ZoneInterface).interfaceId || // ZoneInterface
                          interfaceId == 0x01ffc9a7); // ERC-165
                  }
                  /**
                   * @notice Internal call to return the signing information, substandards,
                   *         and documentation about the zone.
                   *
                   * @return domainSeparator  The domain separator used for signing.
                   * @return zoneName         The zone name.
                   * @return apiEndpoint      The API endpoint for the zone.
                   * @return substandards     The substandards supported by the zone.
                   * @return documentationURI The documentation URI for the zone.
                   */
                  function _sip7Information()
                      internal
                      view
                      returns (
                          bytes32 domainSeparator,
                          string memory zoneName,
                          string memory apiEndpoint,
                          uint256[] memory substandards,
                          string memory documentationURI
                      )
                  {
                      // Return the SIP-7 information.
                      domainSeparator = _domainSeparator();
                      // Get the SIP-7 information from the controller.
                      (
                          ,
                          zoneName,
                          apiEndpoint,
                          substandards,
                          documentationURI
                      ) = SignedZoneControllerInterface(_controller)
                          .getAdditionalZoneInformation(address(this));
                  }
                  /**
                   * @dev Derive the signedOrder hash from the orderHash and expiration.
                   *
                   * @param fulfiller  The expected fulfiller address.
                   * @param expiration The signature expiration timestamp.
                   * @param orderHash  The order hash.
                   * @param context    The optional variable-length context.
                   *
                   * @return signedOrderHash The signedOrder hash.
                   *
                   */
                  function _deriveSignedOrderHash(
                      address fulfiller,
                      uint64 expiration,
                      bytes32 orderHash,
                      bytes calldata context
                  ) internal view returns (bytes32 signedOrderHash) {
                      // Derive the signed order hash.
                      signedOrderHash = keccak256(
                          abi.encode(
                              _SIGNED_ORDER_TYPEHASH,
                              fulfiller,
                              expiration,
                              orderHash,
                              keccak256(context)
                          )
                      );
                  }
                  /**
                   * @dev Internal view function to return the signer of a signature.
                   *
                   * @param digest    The digest to verify the signature against.
                   * @param signature A signature from the signer indicating that the order
                   *                  has been approved.
                   *
                   * @return recoveredSigner The recovered signer.
                   */
                  function _recoverSigner(
                      bytes32 digest,
                      bytes memory signature
                  ) internal view returns (address recoveredSigner) {
                      // Utilize assembly to perform optimized signature verification check.
                      assembly {
                          // Ensure that first word of scratch space is empty.
                          mstore(0, 0)
                          // Declare value for v signature parameter.
                          let v
                          // 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)
                              // 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.
                                  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)
                              }
                          }
                          // Restore the cached values overwritten by selector, digest and
                          // signature head.
                          mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                      }
                  }
                  /**
                   * @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) {
                      // prettier-ignore
                      return block.chainid == _CHAIN_ID
                          ? _DOMAIN_SEPARATOR
                          : _deriveDomainSeparator();
                  }
                  /**
                   * @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(OneWord, nameHash)
                          mstore(TwoWords, versionHash)
                          // Place chainId in the next memory location.
                          mstore(ThreeWords, chainid())
                          // Place the address of this contract in the next memory location.
                          mstore(FourWords, address())
                          // Hash relevant region of memory to derive the domain separator.
                          domainSeparator := keccak256(0, FiveWords)
                          // 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 efficiently derive an digest to sign for
                   *      an order in accordance with EIP-712.
                   *
                   * @param domainSeparator The domain separator.
                   * @param signedOrderHash The signedOrder hash.
                   *
                   * @return digest The digest hash.
                   */
                  function _deriveEIP712Digest(
                      bytes32 domainSeparator,
                      bytes32 signedOrderHash
                  ) internal pure returns (bytes32 digest) {
                      // 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 signed 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_SignedOrderHash_offset, signedOrderHash)
                          // Hash the relevant region
                          digest := keccak256(0, EIP712_DigestPayload_size)
                          // Clear out the dirtied bits in the memory pointer.
                          mstore(EIP712_SignedOrderHash_offset, 0)
                      }
                  }
                  /**
                   * @dev Internal view function to revert if the caller is not the
                   *      controller.
                   */
                  function _assertCallerIsController() internal view {
                      // Get the controller address to use in the assembly block.
                      address controller = _controller;
                      assembly {
                          // Revert if the caller is not the controller.
                          if iszero(eq(caller(), controller)) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidController_error_selector)
                              // revert(abi.encodeWithSignature(
                              //   "InvalidController()")
                              // )
                              revert(0x1c, InvalidController_error_length)
                          }
                      }
                  }
                  /**
                   * @dev Internal pure function to validate calldata offsets for the
                   *      dyanamic type in ZoneParameters. 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.
                   */
                  function _assertValidZoneParameters() internal pure {
                      // Utilize assembly in order to read offset data directly from calldata.
                      assembly {
                          /*
                           * Checks:
                           * 1. Zone parameters struct offset == 0x20
                           */
                          // Zone parameters at calldata 0x04 must have offset of 0x20.
                          if iszero(
                              eq(calldataload(Zone_parameters_cdPtr), Zone_parameters_ptr)
                          ) {
                              // Store left-padded selector with push4 (reduces bytecode),
                              // mem[28:32] = selector
                              mstore(0, InvalidZoneParameterEncoding_error_selector)
                              // revert(abi.encodeWithSignature(
                              //  "InvalidZoneParameterEncoding()"
                              // ))
                              revert(0x1c, InvalidZoneParameterEncoding_error_length)
                          }
                      }
                  }
                  /**
                   * @dev Internal pure function to ensure that the context argument for the
                   *      supplied extra data follows the substandard #1 format. Returns the
                   *      expected fulfiller of the order for deriving the signed order hash.
                   *
                   * @param orderHash The order hash.
                   *
                   * @return expectedFulfiller The expected fulfiller of the order.
                   */
                  function _assertValidSubstandardAndGetExpectedFulfiller(
                      bytes32 orderHash
                  ) internal pure returns (address expectedFulfiller) {
                      // Revert if the expected fulfiller is not the zero address and does
                      // not match the actual fulfiller or if the expected received
                      // identifier does not match the actual received identifier.
                      assembly {
                          // Get the actual fulfiller.
                          let actualFulfiller := calldataload(Zone_parameters_fulfiller_cdPtr)
                          let extraDataPtr := calldataload(Zone_extraData_cdPtr)
                          let considerationPtr := calldataload(Zone_consideration_head_cdPtr)
                          // Get the expected fulfiller.
                          expectedFulfiller := shr(
                              96,
                              calldataload(add(expectedFulfiller_offset, extraDataPtr))
                          )
                          // Get the actual received identifier.
                          let actualReceivedIdentifier := calldataload(
                              add(actualReceivedIdentifier_offset, considerationPtr)
                          )
                          // Get the expected received identifier.
                          let expectedReceivedIdentifier := calldataload(
                              add(expectedReceivedIdentifier_offset, extraDataPtr)
                          )
                          // Revert if expected fulfiller is not the zero address and does
                          // not match the actual fulfiller.
                          if and(
                              iszero(iszero(expectedFulfiller)),
                              iszero(eq(expectedFulfiller, actualFulfiller))
                          ) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidFulfiller_error_selector)
                              mstore(
                                  InvalidFulfiller_error_expectedFulfiller_ptr,
                                  expectedFulfiller
                              )
                              mstore(
                                  InvalidFulfiller_error_actualFulfiller_ptr,
                                  actualFulfiller
                              )
                              mstore(InvalidFulfiller_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //     "InvalidFulfiller(address,address,bytes32)",
                              //     expectedFulfiller,
                              //     actualFulfiller,
                              //     orderHash
                              // ))
                              revert(0x1c, InvalidFulfiller_error_length)
                          }
                          // Revert if expected received item does not match the actual
                          // received item.
                          if iszero(
                              eq(expectedReceivedIdentifier, actualReceivedIdentifier)
                          ) {
                              // Store left-padded selector with push4, mem[28:32] = selector
                              mstore(0, InvalidReceivedItem_error_selector)
                              mstore(
                                  InvalidReceivedItem_error_expectedReceivedItem_ptr,
                                  expectedReceivedIdentifier
                              )
                              mstore(
                                  InvalidReceivedItem_error_actualReceivedItem_ptr,
                                  actualReceivedIdentifier
                              )
                              mstore(InvalidReceivedItem_error_orderHash_ptr, orderHash)
                              // revert(abi.encodeWithSignature(
                              //     "InvalidReceivedItem(uint256,uint256,bytes32)",
                              //     expectedReceivedIdentifier,
                              //     actualReceievedIdentifier,
                              //     orderHash
                              // ))
                              revert(0x1c, InvalidReceivedItem_error_length)
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.13;
              import {
                  BasicOrderType, ItemType, OrderType, Side
              } from "./ConsiderationEnums.sol";
              import { CalldataPointer, MemoryPointer } from "../helpers/PointerLibraries.sol";
              /**
               * @dev An order contains eleven components: an offerer, a zone (or account that
               *      can cancel the order or restrict who can fulfill the order depending on
               *      the type), the order type (specifying partial fill support as well as
               *      restricted order status), the start and end time, a hash that will be
               *      provided to the zone when validating restricted orders, a salt, a key
               *      corresponding to a given conduit, a counter, and an arbitrary number of
               *      offer items that can be spent along with consideration items that must
               *      be received by their respective recipient.
               */
              struct OrderComponents {
                  address offerer;
                  address zone;
                  OfferItem[] offer;
                  ConsiderationItem[] consideration;
                  OrderType orderType;
                  uint256 startTime;
                  uint256 endTime;
                  bytes32 zoneHash;
                  uint256 salt;
                  bytes32 conduitKey;
                  uint256 counter;
              }
              /**
               * @dev An offer item has five components: an item type (ETH or other native
               *      tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and
               *      ERC1155), a token address, a dual-purpose "identifierOrCriteria"
               *      component that will either represent a tokenId or a merkle root
               *      depending on the item type, and a start and end amount that support
               *      increasing or decreasing amounts over the duration of the respective
               *      order.
               */
              struct OfferItem {
                  ItemType itemType;
                  address token;
                  uint256 identifierOrCriteria;
                  uint256 startAmount;
                  uint256 endAmount;
              }
              /**
               * @dev A consideration item has the same five components as an offer item and
               *      an additional sixth component designating the required recipient of the
               *      item.
               */
              struct ConsiderationItem {
                  ItemType itemType;
                  address token;
                  uint256 identifierOrCriteria;
                  uint256 startAmount;
                  uint256 endAmount;
                  address payable recipient;
              }
              /**
               * @dev A spent item is translated from a utilized offer item and has four
               *      components: an item type (ETH or other native tokens, ERC20, ERC721, and
               *      ERC1155), a token address, a tokenId, and an amount.
               */
              struct SpentItem {
                  ItemType itemType;
                  address token;
                  uint256 identifier;
                  uint256 amount;
              }
              /**
               * @dev A received item is translated from a utilized consideration item and has
               *      the same four components as a spent item, as well as an additional fifth
               *      component designating the required recipient of the item.
               */
              struct ReceivedItem {
                  ItemType itemType;
                  address token;
                  uint256 identifier;
                  uint256 amount;
                  address payable recipient;
              }
              /**
               * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155
               *      matching, a group of six functions may be called that only requires a
               *      subset of the usual order arguments. Note the use of a "basicOrderType"
               *      enum; this represents both the usual order type as well as the "route"
               *      of the basic order (a simple derivation function for the basic order
               *      type is `basicOrderType = orderType + (4 * basicOrderRoute)`.)
               */
              struct BasicOrderParameters {
                  // calldata offset
                  address considerationToken; // 0x24
                  uint256 considerationIdentifier; // 0x44
                  uint256 considerationAmount; // 0x64
                  address payable offerer; // 0x84
                  address zone; // 0xa4
                  address offerToken; // 0xc4
                  uint256 offerIdentifier; // 0xe4
                  uint256 offerAmount; // 0x104
                  BasicOrderType basicOrderType; // 0x124
                  uint256 startTime; // 0x144
                  uint256 endTime; // 0x164
                  bytes32 zoneHash; // 0x184
                  uint256 salt; // 0x1a4
                  bytes32 offererConduitKey; // 0x1c4
                  bytes32 fulfillerConduitKey; // 0x1e4
                  uint256 totalOriginalAdditionalRecipients; // 0x204
                  AdditionalRecipient[] additionalRecipients; // 0x224
                  bytes signature; // 0x244
                      // Total length, excluding dynamic array data: 0x264 (580)
              }
              /**
               * @dev Basic orders can supply any number of additional recipients, with the
               *      implied assumption that they are supplied from the offered ETH (or other
               *      native token) or ERC20 token for the order.
               */
              struct AdditionalRecipient {
                  uint256 amount;
                  address payable recipient;
              }
              /**
               * @dev The full set of order components, with the exception of the counter,
               *      must be supplied when fulfilling more sophisticated orders or groups of
               *      orders. The total number of original consideration items must also be
               *      supplied, as the caller may specify additional consideration items.
               */
              struct OrderParameters {
                  address offerer; // 0x00
                  address zone; // 0x20
                  OfferItem[] offer; // 0x40
                  ConsiderationItem[] consideration; // 0x60
                  OrderType orderType; // 0x80
                  uint256 startTime; // 0xa0
                  uint256 endTime; // 0xc0
                  bytes32 zoneHash; // 0xe0
                  uint256 salt; // 0x100
                  bytes32 conduitKey; // 0x120
                  uint256 totalOriginalConsiderationItems; // 0x140
                      // offer.length                          // 0x160
              }
              /**
               * @dev Orders require a signature in addition to the other order parameters.
               */
              struct Order {
                  OrderParameters parameters;
                  bytes signature;
              }
              /**
               * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill)
               *      and a denominator (the total size of the order) in addition to the
               *      signature and other order parameters. It also supports an optional field
               *      for supplying extra data; this data will be provided to the zone if the
               *      order type is restricted and the zone is not the caller, or will be
               *      provided to the offerer as context for contract order types.
               */
              struct AdvancedOrder {
                  OrderParameters parameters;
                  uint120 numerator;
                  uint120 denominator;
                  bytes signature;
                  bytes extraData;
              }
              /**
               * @dev Orders can be validated (either explicitly via `validate`, or as a
               *      consequence of a full or partial fill), specifically cancelled (they can
               *      also be cancelled in bulk via incrementing a per-zone counter), and
               *      partially or fully filled (with the fraction filled represented by a
               *      numerator and denominator).
               */
              struct OrderStatus {
                  bool isValidated;
                  bool isCancelled;
                  uint120 numerator;
                  uint120 denominator;
              }
              /**
               * @dev A criteria resolver specifies an order, side (offer vs. consideration),
               *      and item index. It then provides a chosen identifier (i.e. tokenId)
               *      alongside a merkle proof demonstrating the identifier meets the required
               *      criteria.
               */
              struct CriteriaResolver {
                  uint256 orderIndex;
                  Side side;
                  uint256 index;
                  uint256 identifier;
                  bytes32[] criteriaProof;
              }
              /**
               * @dev A fulfillment is applied to a group of orders. It decrements a series of
               *      offer and consideration items, then generates a single execution
               *      element. A given fulfillment can be applied to as many offer and
               *      consideration items as desired, but must contain at least one offer and
               *      at least one consideration that match. The fulfillment must also remain
               *      consistent on all key parameters across all offer items (same offerer,
               *      token, type, tokenId, and conduit preference) as well as across all
               *      consideration items (token, type, tokenId, and recipient).
               */
              struct Fulfillment {
                  FulfillmentComponent[] offerComponents;
                  FulfillmentComponent[] considerationComponents;
              }
              /**
               * @dev Each fulfillment component contains one index referencing a specific
               *      order and another referencing a specific offer or consideration item.
               */
              struct FulfillmentComponent {
                  uint256 orderIndex;
                  uint256 itemIndex;
              }
              /**
               * @dev An execution is triggered once all consideration items have been zeroed
               *      out. It sends the item in question from the offerer to the item's
               *      recipient, optionally sourcing approvals from either this contract
               *      directly or from the offerer's chosen conduit if one is specified. An
               *      execution is not provided as an argument, but rather is derived via
               *      orders, criteria resolvers, and fulfillments (where the total number of
               *      executions will be less than or equal to the total number of indicated
               *      fulfillments) and returned as part of `matchOrders`.
               */
              struct Execution {
                  ReceivedItem item;
                  address offerer;
                  bytes32 conduitKey;
              }
              /**
               * @dev Restricted orders are validated post-execution by calling validateOrder
               *      on the zone. This struct provides context about the order fulfillment
               *      and any supplied extraData, as well as all order hashes fulfilled in a
               *      call to a match or fulfillAvailable method.
               */
              struct ZoneParameters {
                  bytes32 orderHash;
                  address fulfiller;
                  address offerer;
                  SpentItem[] offer;
                  ReceivedItem[] consideration;
                  bytes extraData;
                  bytes32[] orderHashes;
                  uint256 startTime;
                  uint256 endTime;
                  bytes32 zoneHash;
              }
              /**
               * @dev Zones and contract offerers can communicate which schemas they implement
               *      along with any associated metadata related to each schema.
               */
              struct Schema {
                  uint256 id;
                  bytes metadata;
              }
              using StructPointers for OrderComponents global;
              using StructPointers for OfferItem global;
              using StructPointers for ConsiderationItem global;
              using StructPointers for SpentItem global;
              using StructPointers for ReceivedItem global;
              using StructPointers for BasicOrderParameters global;
              using StructPointers for AdditionalRecipient global;
              using StructPointers for OrderParameters global;
              using StructPointers for Order global;
              using StructPointers for AdvancedOrder global;
              using StructPointers for OrderStatus global;
              using StructPointers for CriteriaResolver global;
              using StructPointers for Fulfillment global;
              using StructPointers for FulfillmentComponent global;
              using StructPointers for Execution global;
              using StructPointers for ZoneParameters global;
              /**
               * @dev This library provides a set of functions for converting structs to
               *      pointers.
               */
              library StructPointers {
                  /**
                   * @dev Get a MemoryPointer from OrderComponents.
                   *
                   * @param obj The OrderComponents object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(OrderComponents memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from OrderComponents.
                   *
                   * @param obj The OrderComponents object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(OrderComponents calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from OfferItem.
                   *
                   * @param obj The OfferItem object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(OfferItem memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from OfferItem.
                   *
                   * @param obj The OfferItem object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(OfferItem calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from ConsiderationItem.
                   *
                   * @param obj The ConsiderationItem object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(ConsiderationItem memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from ConsiderationItem.
                   *
                   * @param obj The ConsiderationItem object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(ConsiderationItem calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from SpentItem.
                   *
                   * @param obj The SpentItem object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(SpentItem memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from SpentItem.
                   *
                   * @param obj The SpentItem object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(SpentItem calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from ReceivedItem.
                   *
                   * @param obj The ReceivedItem object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(ReceivedItem memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from ReceivedItem.
                   *
                   * @param obj The ReceivedItem object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(ReceivedItem calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from BasicOrderParameters.
                   *
                   * @param obj The BasicOrderParameters object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(BasicOrderParameters memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from BasicOrderParameters.
                   *
                   * @param obj The BasicOrderParameters object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(BasicOrderParameters calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from AdditionalRecipient.
                   *
                   * @param obj The AdditionalRecipient object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(AdditionalRecipient memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from AdditionalRecipient.
                   *
                   * @param obj The AdditionalRecipient object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(AdditionalRecipient calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from OrderParameters.
                   *
                   * @param obj The OrderParameters object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(OrderParameters memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from OrderParameters.
                   *
                   * @param obj The OrderParameters object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(OrderParameters calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from Order.
                   *
                   * @param obj The Order object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(Order memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from Order.
                   *
                   * @param obj The Order object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(Order calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from AdvancedOrder.
                   *
                   * @param obj The AdvancedOrder object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(AdvancedOrder memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from AdvancedOrder.
                   *
                   * @param obj The AdvancedOrder object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(AdvancedOrder calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from OrderStatus.
                   *
                   * @param obj The OrderStatus object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(OrderStatus memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from OrderStatus.
                   *
                   * @param obj The OrderStatus object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(OrderStatus calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from CriteriaResolver.
                   *
                   * @param obj The CriteriaResolver object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(CriteriaResolver memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from CriteriaResolver.
                   *
                   * @param obj The CriteriaResolver object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(CriteriaResolver calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from Fulfillment.
                   *
                   * @param obj The Fulfillment object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(Fulfillment memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from Fulfillment.
                   *
                   * @param obj The Fulfillment object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(Fulfillment calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from FulfillmentComponent.
                   *
                   * @param obj The FulfillmentComponent object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(FulfillmentComponent memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from FulfillmentComponent.
                   *
                   * @param obj The FulfillmentComponent object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(FulfillmentComponent calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from Execution.
                   *
                   * @param obj The Execution object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(Execution memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from Execution.
                   *
                   * @param obj The Execution object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(Execution calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a MemoryPointer from ZoneParameters.
                   *
                   * @param obj The ZoneParameters object.
                   *
                   * @return ptr The MemoryPointer.
                   */
                  function toMemoryPointer(ZoneParameters memory obj)
                      internal
                      pure
                      returns (MemoryPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
                  /**
                   * @dev Get a CalldataPointer from ZoneParameters.
                   *
                   * @param obj The ZoneParameters object.
                   *
                   * @return ptr The CalldataPointer.
                   */
                  function toCalldataPointer(ZoneParameters calldata obj)
                      internal
                      pure
                      returns (CalldataPointer ptr)
                  {
                      assembly {
                          ptr := obj
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.13;
              import { ZoneInterface } from "seaport-types/src/interfaces/ZoneInterface.sol";
              interface LocalZoneInterface is ZoneInterface { }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              /**
               * @notice SignedZoneEventsAndErrors contains errors and events
               *         related to zone interaction.
               */
              interface SignedZoneEventsAndErrors {
                  /**
                   * @dev Emit an event when a new signer is added.
                   */
                  event SignerAdded(address signer);
                  /**
                   * @dev Emit an event when a signer is removed.
                   */
                  event SignerRemoved(address signer);
                  /**
                   * @dev Revert with an error when the signature has expired.
                   */
                  error SignatureExpired(uint256 expiration, bytes32 orderHash);
                  /**
                   * @dev Revert with an error when the caller is not seaport.
                   */
                  error CallerNotSeaport();
                  /**
                   * @dev Revert with an error when attempting to update the signers of a
                   *      the zone from a caller that is not the zone's controller.
                   */
                  error InvalidController();
                  /**
                   * @dev Revert with an error if supplied order extraData is an invalid
                   *      length.
                   */
                  error InvalidExtraDataLength(bytes32 orderHash);
                  /**
                   * @dev Revert with an error if the supplied order extraData does not
                   *      support the zone's SIP6 version.
                   */
                  error InvalidSIP6Version(bytes32 orderHash);
                  /**
                   * @dev Revert with an error if the supplied order extraData does not
                   *      support the zone's substandard requirements.
                   */
                  error InvalidSubstandardSupport(
                      string reason,
                      uint256 substandardVersion,
                      bytes32 orderHash
                  );
                  /**
                   * @dev Revert with an error if the supplied order extraData does not
                   *      support the zone's substandard version.
                   */
                  error InvalidSubstandardVersion(bytes32 orderHash);
                  /**
                   * @dev Revert with an error if the fulfiller does not match.
                   */
                  error InvalidFulfiller(
                      address expectedFulfiller,
                      address actualFulfiller,
                      bytes32 orderHash
                  );
                  /**
                   * @dev Revert with an error if the received item does not match.
                   */
                  error InvalidReceivedItem(
                      uint256 expectedReceivedIdentifier,
                      uint256 actualReceievedIdentifier,
                      bytes32 orderHash
                  );
                  /**
                   * @dev Revert with an error if the zone parameter encoding is invalid.
                   */
                  error InvalidZoneParameterEncoding();
                  /**
                   * @dev Revert with an error when an order is signed with a signer
                   *      that is not active.
                   */
                  error SignerNotActive(address signer, bytes32 orderHash);
                  /**
                   * @dev Revert when an unsupported function selector is found.
                   */
                  error UnsupportedFunctionSelector();
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              import { Schema } from "../../../types/lib/ConsiderationStructs.sol";
              /**
               * @dev SIP-5: Contract Metadata Interface for Seaport Contracts
               *      https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-5.md
               */
              interface SIP5Interface {
                  /**
                   * @dev An event that is emitted when a SIP-5 compatible contract is deployed.
                   */
                  event SeaportCompatibleContractDeployed();
                  /**
                   * @dev Returns Seaport metadata for this contract, returning the
                   *      contract name and supported schemas.
                   *
                   * @return name    The contract name
                   * @return schemas The supported SIPs
                   */
                  function getSeaportMetadata()
                      external
                      view
                      returns (string memory name, Schema[] memory schemas);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              /**
               * @title  SignedZoneControllerInterface
               * @author BCLeFevre
               * @notice SignedZoneControllerInterface enables the deploying of SignedZones.
               *         SignedZones are an implementation of SIP-7 that requires orders
               *         to be signed by an approved signer.
               *         https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md
               *
               */
              interface SignedZoneControllerInterface {
                  /**
                   * @notice Returns the active signers for the zone.
                   *
                   * @param signedZone The signed zone to get the active signers for.
                   *
                   * @return signers The active signers.
                   */
                  function getActiveSigners(
                      address signedZone
                  ) external view returns (address[] memory signers);
                  /**
                   * @notice Returns additional information about the zone.
                   *
                   * @param zone The zone to get the additional information for.
                   *
                   * @return domainSeparator  The domain separator used for signing.
                   * @return zoneName         The name of the zone.
                   * @return apiEndpoint      The API endpoint for the zone.
                   * @return substandards     The substandards supported by the zone.
                   * @return documentationURI The documentation URI for the zone.
                   */
                  function getAdditionalZoneInformation(
                      address zone
                  )
                      external
                      view
                      returns (
                          bytes32 domainSeparator,
                          string memory zoneName,
                          string memory apiEndpoint,
                          uint256[] memory substandards,
                          string memory documentationURI
                      );
                  /**
                   * @notice Update the API endpoint returned by the supplied zone.
                   *         Only the owner or an active signer can call this function.
                   *
                   * @param signedZone     The signed zone to update the API endpoint for.
                   * @param newApiEndpoint The new API endpoint.
                   */
                  function updateAPIEndpoint(
                      address signedZone,
                      string calldata newApiEndpoint
                  ) external;
                  /**
                   * @notice Update the documentationURI returned by a zone.
                   *         Only the owner or an active signer of the supplied zone can call
                   *         this function.
                   *
                   * @param zone             The signed zone to update the API endpoint for.
                   * @param documentationURI The new documentation URI.
                   */
                  function updateDocumentationURI(
                      address zone,
                      string calldata documentationURI
                  ) external;
                  /**
                   * @notice Update the signer for a given signed zone.
                   *
                   * @param signedZone The signed zone to update the signer for.
                   * @param signer     The signer to update.
                   * @param active     If the signer should be active or not.
                   */
                  function updateSigner(
                      address signedZone,
                      address signer,
                      bool active
                  ) external;
                  /**
                   * @notice Initiate zone ownership transfer by assigning a new potential
                   *         owner for the given zone. Once set, the new potential owner
                   *         may call `acceptOwnership` to claim ownership of the zone.
                   *         Only the owner of the zone in question may call this function.
                   *
                   * @param zone              The zone for which to initiate ownership
                   *                          transfer.
                   * @param newPotentialOwner The new potential owner of the zone.
                   */
                  function transferOwnership(
                      address zone,
                      address newPotentialOwner
                  ) external;
                  /**
                   * @notice Clear the currently set potential owner, if any, from a zone.
                   *         Only the owner of the zone in question may call this function.
                   *
                   * @param zone The zone for which to cancel ownership transfer.
                   */
                  function cancelOwnershipTransfer(address zone) external;
                  /**
                   * @notice Accept ownership of a supplied zone. Only accounts that the
                   *         current owner has set as the new potential owner may call this
                   *         function.
                   *
                   * @param zone The zone for which to accept ownership.
                   */
                  function acceptOwnership(address zone) external;
                  /**
                   * @notice Retrieve the current owner of a deployed zone.
                   *
                   * @param zone The zone for which to retrieve the associated owner.
                   *
                   * @return owner The owner of the supplied zone.
                   */
                  function ownerOf(address zone) external view returns (address owner);
                  /**
                   * @notice Retrieve the potential owner, if any, for a given zone. The
                   *         current owner may set a new potential owner via
                   *         `transferOwnership` and that owner may then accept ownership of
                   *         the zone in question via `acceptOwnership`.
                   *
                   * @param zone The zone for which to retrieve the potential owner.
                   *
                   * @return potentialOwner The potential owner, if any, for the zone.
                   */
                  function getPotentialOwner(
                      address zone
                  ) external view returns (address potentialOwner);
                  /**
                   * @notice Returns whether or not the supplied address is an active signer
                   *         for the supplied zone.
                   *
                   * @param zone   The zone to check if the supplied address is an active
                   *               signer for.
                   * @param signer The address to check if it is an active signer for
                   *
                   * @return active If the supplied address is an active signer for the
                   *                supplied zone.
                   */
                  function isActiveSigner(
                      address zone,
                      address signer
                  ) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              enum ListTypes {
                  AuthorizerList,
                  OperatorList
              }
              /// @title IAuthorizedTransferSecurityRegistry
              /// @dev Interface for the Authorized Transfer Security Registry, a simplified version of the Transfer
              ///      Security Registry that only supports authorizers and whitelisted operators, and assumes a
              ///      security level of OperatorWhitelistEnableOTC + authorizers for all collections that use it.
              ///      Note that a number of view functions on collections that add this validator will not work.
              interface IAuthorizedTransferSecurityRegistry {
                  event CreatedList(uint256 indexed id, string name);
                  event AppliedListToCollection(address indexed collection, uint120 indexed id);
                  event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
                  event AddedAccountToList(ListTypes indexed kind, uint256 indexed id, address indexed account);
                  event RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account);
                  error AuthorizedTransferSecurityRegistry__ListDoesNotExist();
                  error AuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
                  error AuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
                  error AuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
                  error AuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
                  error AuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed();
                  error AuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                  error AuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();
                  /// Manage lists of authorizers & operators that can be applied to collections
                  function createList(string calldata name) external returns (uint120);
                  function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120);
                  function reassignOwnershipOfList(uint120 id, address newOwner) external;
                  function renounceOwnershipOfList(uint120 id) external;
                  function applyListToCollection(address collection, uint120 id) external;
                  function listOwners(uint120 id) external view returns (address);
                  /// Manage and query for authorizers on lists
                  function addAuthorizers(uint120 id, address[] calldata accounts) external;
                  function removeAuthorizers(uint120 id, address[] calldata accounts) external;
                  function getAuthorizers(uint120 id) external view returns (address[] memory);
                  function isAuthorizer(uint120 id, address account) external view returns (bool);
                  function getAuthorizersByCollection(address collection) external view returns (address[] memory);
                  function isAuthorizerByCollection(address collection, address account) external view returns (bool);
                  /// Manage and query for operators on lists
                  function addOperators(uint120 id, address[] calldata accounts) external;
                  function removeOperators(uint120 id, address[] calldata accounts) external;
                  function getOperators(uint120 id) external view returns (address[] memory);
                  function isOperator(uint120 id, address account) external view returns (bool);
                  function getOperatorsByCollection(address collection) external view returns (address[] memory);
                  function isOperatorByCollection(address collection, address account) external view returns (bool);
                  /// Ensure that a specific operator has been authorized to transfer tokens
                  function validateTransfer(address caller, address from, address to) external view;
                  /// Ensure that a transfer has been authorized for a specific tokenId
                  function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
                  /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
                  /// reduce the transferable amount remaining
                  function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
                  /// Legacy alias for validateTransfer (address caller, address from, address to)
                  function applyCollectionTransferPolicy(address caller, address from, address to) external view;
                  /// Temporarily assign a specific allowed operator for a given collection
                  function beforeAuthorizedTransfer(address operator, address token) external;
                  /// Clear assignment of a specific allowed operator for a given collection
                  function afterAuthorizedTransfer(address token) external;
                  /// Temporarily allow a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
                  /// Clear assignment of an specific tokenId's transfer allowance
                  function afterAuthorizedTransfer(address token, uint256 tokenId) external;
                  /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
                  /// Clear assignment of a tokenId's transfer allowance for a specific amount
                  function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
              }// SPDX-License-Identifier: MIT
              pragma solidity ^0.8.19;
              /// @dev ECDSA signature offsets.
              uint256 constant ECDSA_MaxLength = 65;
              uint256 constant ECDSA_signature_s_offset = 0x40;
              uint256 constant ECDSA_signature_v_offset = 0x60;
              /// @dev Helpers for memory offsets.
              uint256 constant OneWord = 0x20;
              uint256 constant TwoWords = 0x40;
              uint256 constant ThreeWords = 0x60;
              uint256 constant FourWords = 0x80;
              uint256 constant FiveWords = 0xa0;
              uint256 constant Signature_lower_v = 27;
              uint256 constant MaxUint8 = 0xff;
              bytes32 constant EIP2098_allButHighestBitMask = (
                  0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
              );
              uint256 constant Ecrecover_precompile = 1;
              uint256 constant Ecrecover_args_size = 0x80;
              uint256 constant FreeMemoryPointerSlot = 0x40;
              uint256 constant ZeroSlot = 0x60;
              uint256 constant Slot0x80 = 0x80;
              /// @dev The EIP-712 digest offsets.
              uint256 constant EIP712_DomainSeparator_offset = 0x02;
              uint256 constant EIP712_SignedOrderHash_offset = 0x22;
              uint256 constant EIP712_DigestPayload_size = 0x42;
              uint256 constant EIP_712_PREFIX = (
                  0x1901000000000000000000000000000000000000000000000000000000000000
              );
              // @dev Function selectors used in the fallback function..
              bytes4 constant UPDATE_SIGNER_SELECTOR = 0xf460590b;
              bytes4 constant GET_ACTIVE_SIGNERS_SELECTOR = 0xa784b80c;
              bytes4 constant IS_ACTIVE_SIGNER_SELECTOR = 0x7dff5a79;
              bytes4 constant SUPPORTS_INTERFACE_SELECTOR = 0x01ffc9a7;
              /*
               *  error InvalidController()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               * Revert buffer is memory[0x1c:0x20]
               */
              uint256 constant InvalidController_error_selector = 0x6d5769be;
              uint256 constant InvalidController_error_length = 0x04;
              /*
               *  error InvalidFulfiller(address expectedFulfiller, address actualFulfiller, bytes32 orderHash)
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               *    - 0x20: expectedFulfiller
               *    - 0x40: actualFullfiller
               *    - 0x60: orderHash
               * Revert buffer is memory[0x1c:0x80]
               */
              uint256 constant InvalidFulfiller_error_selector = 0x1bcf9bb7;
              uint256 constant InvalidFulfiller_error_expectedFulfiller_ptr = 0x20;
              uint256 constant InvalidFulfiller_error_actualFulfiller_ptr = 0x40;
              uint256 constant InvalidFulfiller_error_orderHash_ptr = 0x60;
              uint256 constant InvalidFulfiller_error_length = 0x64;
              /*
               *  error InvalidReceivedItem(uint256 expectedReceivedIdentifier, uint256 actualReceievedIdentifier, bytes32 orderHash)
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               *    - 0x20: expectedReceivedIdentifier
               *    - 0x40: actualReceievedIdentifier
               *    - 0x60: orderHash
               * Revert buffer is memory[0x1c:0x80]
               */
              uint256 constant InvalidReceivedItem_error_selector = 0xb36c03e8;
              uint256 constant InvalidReceivedItem_error_expectedReceivedItem_ptr = 0x20;
              uint256 constant InvalidReceivedItem_error_actualReceivedItem_ptr = 0x40;
              uint256 constant InvalidReceivedItem_error_orderHash_ptr = 0x60;
              uint256 constant InvalidReceivedItem_error_length = 0x64;
              /*
               *  error InvalidZoneParameterEncoding()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               * Revert buffer is memory[0x1c:0x20]
               */
              uint256 constant InvalidZoneParameterEncoding_error_selector = 0x46d5d895;
              uint256 constant InvalidZoneParameterEncoding_error_length = 0x04;
              /*
               * error InvalidExtraDataLength()
               *   - Defined in SignedZoneEventsAndErrors.sol
               * Memory layout:
               *   - 0x00: Left-padded selector (data begins at 0x1c)
               *   - 0x20: orderHash
               * Revert buffer is memory[0x1c:0x40]
               */
              uint256 constant InvalidExtraDataLength_error_selector = 0xd232fd2c;
              uint256 constant InvalidExtraDataLength_error_orderHash_ptr = 0x20;
              uint256 constant InvalidExtraDataLength_error_length = 0x24;
              uint256 constant InvalidExtraDataLength_expected_length_substandard_1 = 0x7e; // 126
              uint256 constant InvalidExtraDataLength_expected_length_substandard_7 = 0xa6; // 166
              uint256 constant InvalidExtraDataLength_expected_length_substandard_8_or_9 = 0x92; // 146
              uint256 constant ExtraData_expiration_offset = 0x35;
              uint256 constant ExtraData_substandard_version_byte_offset = 0x7d;
              /*
               *  error InvalidSIP6Version()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               *    - 0x20: orderHash
               * Revert buffer is memory[0x1c:0x40]
               */
              uint256 constant InvalidSIP6Version_error_selector = 0x64115774;
              uint256 constant InvalidSIP6Version_error_orderHash_ptr = 0x20;
              uint256 constant InvalidSIP6Version_error_length = 0x24;
              /*
               *  error InvalidSubstandardVersion()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               *    - 0x20: orderHash
               * Revert buffer is memory[0x1c:0x40]
               */
              uint256 constant InvalidSubstandardVersion_error_selector = 0x26787999;
              uint256 constant InvalidSubstandardVersion_error_orderHash_ptr = 0x20;
              uint256 constant InvalidSubstandardVersion_error_length = 0x24;
              /*
               *  error InvalidSubstandardSupport()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               *    - 0x20: reason
               *    - 0x40: substandardVersion
               *    - 0x60: orderHash
               * Revert buffer is memory[0x1c:0xe0]
               */
              uint256 constant InvalidSubstandardSupport_error_selector = 0x2be76224;
              uint256 constant InvalidSubstandardSupport_error_reason_offset_ptr = 0x20;
              uint256 constant InvalidSubstandardSupport_error_substandard_version_ptr = 0x40;
              uint256 constant InvalidSubstandardSupport_error_orderHash_ptr = 0x60;
              uint256 constant InvalidSubstandardSupport_error_reason_length_ptr = 0x80;
              uint256 constant InvalidSubstandardSupport_error_reason_ptr = 0xa0;
              uint256 constant InvalidSubstandardSupport_error_reason_2_ptr = 0xc0;
              uint256 constant InvalidSubstandardSupport_error_length = 0xc4;
              /*
               * error SignatureExpired()
               *   - Defined in SignedZoneEventsAndErrors.sol
               * Memory layout:
               *   - 0x00: Left-padded selector (data begins at 0x1c)
               *   - 0x20: expiration
               *   - 0x40: orderHash
               * Revert buffer is memory[0x1c:0x60]
               */
              uint256 constant SignatureExpired_error_selector = 0x16546071;
              uint256 constant SignatureExpired_error_expiration_ptr = 0x20;
              uint256 constant SignatureExpired_error_orderHash_ptr = 0x40;
              uint256 constant SignatureExpired_error_length = 0x44;
              /*
               *  error UnsupportedFunctionSelector()
               *    - Defined in SignedZoneEventsAndErrors.sol
               *  Memory layout:
               *    - 0x00: Left-padded selector (data begins at 0x1c)
               * Revert buffer is memory[0x1c:0x20]
               */
              uint256 constant UnsupportedFunctionSelector_error_selector = 0x54c91b87;
              uint256 constant UnsupportedFunctionSelector_error_length = 0x04;
              // Zone parameter calldata pointers
              uint256 constant Zone_parameters_cdPtr = 0x04;
              uint256 constant Zone_parameters_fulfiller_cdPtr = 0x44;
              uint256 constant Zone_consideration_head_cdPtr = 0xa4;
              uint256 constant Zone_extraData_cdPtr = 0xc4;
              // Zone parameter memory pointers
              uint256 constant Zone_parameters_ptr = 0x20;
              // Zone parameter offsets
              uint256 constant Zone_parameters_offset = 0x24;
              uint256 constant expectedFulfiller_offset = 0x45;
              uint256 constant actualReceivedIdentifier_offset = 0x84;
              uint256 constant expectedReceivedIdentifier_offset = 0xa2;
              // Spent Item Size
              uint256 constant SpentItem_size = 0x80;
              // Received Item Size
              uint256 constant ReceivedItem_size = 0xa0;
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.13;
              enum OrderType
              // 0: no partial fills, anyone can execute
              {
                  FULL_OPEN,
                  // 1: partial fills supported, anyone can execute
                  PARTIAL_OPEN,
                  // 2: no partial fills, only offerer or zone can execute
                  FULL_RESTRICTED,
                  // 3: partial fills supported, only offerer or zone can execute
                  PARTIAL_RESTRICTED,
                  // 4: contract order type
                  CONTRACT
              }
              enum BasicOrderType
              // 0: no partial fills, anyone can execute
              {
                  ETH_TO_ERC721_FULL_OPEN,
                  // 1: partial fills supported, anyone can execute
                  ETH_TO_ERC721_PARTIAL_OPEN,
                  // 2: no partial fills, only offerer or zone can execute
                  ETH_TO_ERC721_FULL_RESTRICTED,
                  // 3: partial fills supported, only offerer or zone can execute
                  ETH_TO_ERC721_PARTIAL_RESTRICTED,
                  // 4: no partial fills, anyone can execute
                  ETH_TO_ERC1155_FULL_OPEN,
                  // 5: partial fills supported, anyone can execute
                  ETH_TO_ERC1155_PARTIAL_OPEN,
                  // 6: no partial fills, only offerer or zone can execute
                  ETH_TO_ERC1155_FULL_RESTRICTED,
                  // 7: partial fills supported, only offerer or zone can execute
                  ETH_TO_ERC1155_PARTIAL_RESTRICTED,
                  // 8: no partial fills, anyone can execute
                  ERC20_TO_ERC721_FULL_OPEN,
                  // 9: partial fills supported, anyone can execute
                  ERC20_TO_ERC721_PARTIAL_OPEN,
                  // 10: no partial fills, only offerer or zone can execute
                  ERC20_TO_ERC721_FULL_RESTRICTED,
                  // 11: partial fills supported, only offerer or zone can execute
                  ERC20_TO_ERC721_PARTIAL_RESTRICTED,
                  // 12: no partial fills, anyone can execute
                  ERC20_TO_ERC1155_FULL_OPEN,
                  // 13: partial fills supported, anyone can execute
                  ERC20_TO_ERC1155_PARTIAL_OPEN,
                  // 14: no partial fills, only offerer or zone can execute
                  ERC20_TO_ERC1155_FULL_RESTRICTED,
                  // 15: partial fills supported, only offerer or zone can execute
                  ERC20_TO_ERC1155_PARTIAL_RESTRICTED,
                  // 16: no partial fills, anyone can execute
                  ERC721_TO_ERC20_FULL_OPEN,
                  // 17: partial fills supported, anyone can execute
                  ERC721_TO_ERC20_PARTIAL_OPEN,
                  // 18: no partial fills, only offerer or zone can execute
                  ERC721_TO_ERC20_FULL_RESTRICTED,
                  // 19: partial fills supported, only offerer or zone can execute
                  ERC721_TO_ERC20_PARTIAL_RESTRICTED,
                  // 20: no partial fills, anyone can execute
                  ERC1155_TO_ERC20_FULL_OPEN,
                  // 21: partial fills supported, anyone can execute
                  ERC1155_TO_ERC20_PARTIAL_OPEN,
                  // 22: no partial fills, only offerer or zone can execute
                  ERC1155_TO_ERC20_FULL_RESTRICTED,
                  // 23: partial fills supported, only offerer or zone can execute
                  ERC1155_TO_ERC20_PARTIAL_RESTRICTED
              }
              enum BasicOrderRouteType
              // 0: provide Ether (or other native token) to receive offered ERC721 item.
              {
                  ETH_TO_ERC721,
                  // 1: provide Ether (or other native token) to receive offered ERC1155 item.
                  ETH_TO_ERC1155,
                  // 2: provide ERC20 item to receive offered ERC721 item.
                  ERC20_TO_ERC721,
                  // 3: provide ERC20 item to receive offered ERC1155 item.
                  ERC20_TO_ERC1155,
                  // 4: provide ERC721 item to receive offered ERC20 item.
                  ERC721_TO_ERC20,
                  // 5: provide ERC1155 item to receive offered ERC20 item.
                  ERC1155_TO_ERC20
              }
              enum ItemType
              // 0: ETH on mainnet, MATIC on polygon, etc.
              {
                  NATIVE,
                  // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work)
                  ERC20,
                  // 2: ERC721 items
                  ERC721,
                  // 3: ERC1155 items
                  ERC1155,
                  // 4: ERC721 items where a number of tokenIds are supported
                  ERC721_WITH_CRITERIA,
                  // 5: ERC1155 items where a number of ids are supported
                  ERC1155_WITH_CRITERIA
              }
              enum Side
              // 0: Items that can be spent
              {
                  OFFER,
                  // 1: Items that must be received
                  CONSIDERATION
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.13;
              type CalldataPointer is uint256;
              type ReturndataPointer is uint256;
              type MemoryPointer is uint256;
              using CalldataPointerLib for CalldataPointer global;
              using MemoryPointerLib for MemoryPointer global;
              using ReturndataPointerLib for ReturndataPointer global;
              using CalldataReaders for CalldataPointer global;
              using ReturndataReaders for ReturndataPointer global;
              using MemoryReaders for MemoryPointer global;
              using MemoryWriters for MemoryPointer global;
              CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04);
              MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40);
              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;
              import { ZoneParameters, Schema } from "../lib/ConsiderationStructs.sol";
              import { IERC165 } from "./IERC165.sol";
              /**
               * @title  ZoneInterface
               * @notice Contains functions exposed by a zone.
               */
              interface ZoneInterface is IERC165 {
                  /**
                   * @dev Authorizes an order before any token fulfillments from any order have been executed by Seaport.
                   *
                   * @param zoneParameters The context about the order fulfillment and any
                   *                       supplied extraData.
                   *
                   * @return authorizedOrderMagicValue The magic value that indicates a valid
                   *                              order.
                   */
                  function authorizeOrder(ZoneParameters calldata zoneParameters)
                      external
                      returns (bytes4 authorizedOrderMagicValue);
                  /**
                   * @dev Validates an order after all token fulfillments for all orders have been executed by Seaport.
                   *
                   * @param zoneParameters The context about the order fulfillment and any
                   *                       supplied extraData.
                   *
                   * @return validOrderMagicValue The magic value that indicates a valid
                   *                              order.
                   */
                  function validateOrder(ZoneParameters calldata zoneParameters)
                      external
                      returns (bytes4 validOrderMagicValue);
                  /**
                   * @dev Returns the metadata for this zone.
                   *
                   * @return name The name of the zone.
                   * @return schemas The schemas that the zone implements.
                   */
                  function getSeaportMetadata()
                      external
                      view
                      returns (string memory name, Schema[] memory schemas); // map to Seaport Improvement Proposal IDs
                  /**
                  * @dev Returns if the zone supports the interfaceId.
                  *
                  * @param interfaceId The interface identifier, as specified in ERC-165.
                  *
                  * @return supportsInterface True if the zone supports interfaceId, false
                  */
                  function supportsInterface(bytes4 interfaceId)
                      external
                      view
                      override
                      returns (bool supportsInterface);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
              pragma solidity ^0.8.7;
              /**
               * @dev Interface of the ERC165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[EIP].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                  /**
                   * @dev Returns true if this contract implements the interface defined by
                   * `interfaceId`.
                   *
                   * This function call must use less than 30 000 gas.
                   */
                  function supportsInterface(bytes4 interfaceId)
                      external
                      view
                      returns (bool);
              }
              

              File 4 of 5: StrictAuthorizedTransferSecurityRegistry
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              import {
                  ListTypes,
                  TransferSecurityLevels,
                  IStrictAuthorizedTransferSecurityRegistry
              } from "./interfaces/IStrictAuthorizedTransferSecurityRegistry.sol";
              import {
                  ICreatorTokenTransferValidator
              } from "./interfaces/ICreatorTokenTransferValidator.sol";
              import { IOwnable } from "./interfaces/IOwnable.sol";
              import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
              import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
              import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
              import { Tstorish } from "tstorish/Tstorish.sol";
              import { IEOARegistry } from "./interfaces/IEOARegistry.sol";
              import {
                  StrictAuthorizedTransferSecurityRegistryExtraViewFns
              } from "./StrictAuthorizedTransferSecurityRegistryExtraViewFns.sol";
              /// @title StrictAuthorizedTransferSecurityRegistry
              /// @dev Implementation of a simplified version of the Transfer Security Registry that only
              ///      supports authorizers and whitelisted operators, and allows collections to disable
              ///      direct transfers (where caller == from) and contract recipients (requiring EOA
              ///      registration by providing a signature). Note that a number of view functions on
              ///      collections that add this validator will not work.
              contract StrictAuthorizedTransferSecurityRegistry is Tstorish, IStrictAuthorizedTransferSecurityRegistry, ERC165 {
                  using EnumerableSet for EnumerableSet.AddressSet;
                  /**
                   * @dev This struct is used internally to represent an enumerable list of accounts.
                   */
                  struct AccountList {
                      EnumerableSet.AddressSet enumerableAccounts;
                      mapping (address => bool) nonEnumerableAccounts;
                  }
                  /**
                   * @dev This struct is used internally for the storage of authorizer + operator lists.
                   */
                  struct List {
                      address owner;
                      AccountList authorizers;
                      AccountList operators;
                      AccountList blacklist;
                  }
                  struct CollectionConfiguration {
                      uint120 listId;
                      bool policyBypassed;
                      bool blacklistBased;
                      bool directTransfersDisabled;
                      bool contractRecipientsDisabled;
                      bool signatureRegistrationRequired;
                  }
                  
                  /// @dev The default admin role value for contracts that implement access control.
                  bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
                  /// @notice Keeps track of the most recently created list id.
                  uint120 public lastListId;
                  /// @dev Mapping of list ids to list settings
                  mapping (uint120 => List) private lists;
                  /// @dev Mapping of collection addresses to list ids & security policies.
                  mapping (address => CollectionConfiguration) private collectionConfiguration;
                  // TSTORE slot: scope ++ 8 empty bytes ++ collection
                  bytes4 private constant _AUTHORIZED_OPERATOR_SCOPE = 0x596a397a;
                  // TSTORE slot: keccak256(scope ++ identifier ++ collection)
                  bytes4 private constant _AUTHORIZED_IDENTIFIER_SCOPE = 0x7e746c61;
                  // TSTORE slot: keccak256(scope ++ identifier ++ collection)
                  bytes4 private constant _AUTHORIZED_AMOUNT_SCOPE = 0x71836d45;
                  address private immutable _EXTRA_VIEW_FUNCTIONS;
                  IEOARegistry private immutable _EOA_REGISTRY;
                  /**
                   * @dev This modifier restricts a function call to the owner of the list `id`.
                   * @dev Throws when the caller is not the list owner.
                   */
                  modifier onlyListOwner(uint120 id) {
                      _requireCallerOwnsList(id);
                      _;
                  }
                  /**
                   * @dev This modifier reverts a transaction if the supplied array has a zero length.
                   * @dev Throws when the array parameter has a zero length.
                   */
                  modifier notZero(uint256 value) {
                      if (value == 0) {
                          revert StrictAuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
                      }
                      _;
                  }
                  constructor(address defaultOwner, address eoaRegistry) {
                      uint120 id = 0;
                      lists[id].owner = defaultOwner;
                      emit CreatedList(id, "DEFAULT LIST");
                      emit ReassignedListOwnership(id, defaultOwner);
                      // Deploy a contract containing legacy view functions.
                      _EXTRA_VIEW_FUNCTIONS = address(new StrictAuthorizedTransferSecurityRegistryExtraViewFns());
                      _EOA_REGISTRY = IEOARegistry(eoaRegistry);
                  }
                  // Delegatecall to contract with legacy view functions in the fallback.
                  fallback() external {
                      address target = _EXTRA_VIEW_FUNCTIONS;
                      assembly {
                          calldatacopy(0, 0, calldatasize())
                          let status := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
                          returndatacopy(0, 0, returndatasize())
                          switch status
                          case 0 {
                              revert(0, returndatasize())
                          }
                          default {
                              return(0, returndatasize())
                          }
                      }
                  }
                  /// Manage lists of authorizers & operators that can be applied to collections
                  function createList(string calldata name) external returns (uint120) {
                      uint120 id = ++lastListId;
                      lists[id].owner = msg.sender;
                      emit CreatedList(id, name);
                      emit ReassignedListOwnership(id, msg.sender);
                      return id;
                  }
                  function createListCopy(string calldata name, uint120 sourceListId) external override returns (uint120) {
                      uint120 id = ++lastListId;
                      unchecked {
                          if (sourceListId > id - 1) {
                              revert StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist();
                          }
                      }
                      List storage sourceList = lists[sourceListId];
                      List storage targetList = lists[id];
                      targetList.owner = msg.sender;
                      emit CreatedList(id, name);
                      emit ReassignedListOwnership(id, msg.sender);
                      _copyAddressSet(ListTypes.AuthorizerList, id, sourceList.authorizers, targetList.authorizers);
                      _copyAddressSet(ListTypes.OperatorList, id, sourceList.operators, targetList.operators);
                      _copyAddressSet(ListTypes.OperatorRequiringAuthorizationList, id, sourceList.blacklist, targetList.blacklist);
                      return id;
                  }
                  function reassignOwnershipOfList(uint120 id, address newOwner) external onlyListOwner(id) {
                      if (newOwner == address(0)) {
                          revert StrictAuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
                      }
                      lists[id].owner = newOwner;
                      emit ReassignedListOwnership(id, newOwner);
                  }
                  function renounceOwnershipOfList(uint120 id) external onlyListOwner(id) {
                      lists[id].owner = address(0);
                      emit ReassignedListOwnership(id, address(0));
                  }
                  function applyListToCollection(address collection, uint120 id) external {
                      _requireCallerIsNFTOrContractOwnerOrAdmin(collection);
                      if (id > lastListId) {
                          revert StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist();
                      }
                      collectionConfiguration[collection].listId = id;
                      emit AppliedListToCollection(collection, id);
                  }
                  function listOwners(uint120 id) external view returns (address) {
                      return lists[id].owner;
                  }
                  /// Manage and query for authorizers on lists
                  function addAccountToAuthorizers(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
                  }
                  function addAccountsToAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
                  }
                  function addAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
                  }
                  function removeAccountFromAuthorizers(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _removeAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
                  }
                  
                  function removeAccountsFromAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _removeAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
                  }
                  function getAuthorizerAccounts(uint120 id) external view returns (address[] memory) {
                      return lists[id].authorizers.enumerableAccounts.values();
                  }
                  function isAccountAuthorizer(uint120 id, address account) external view returns (bool) {
                      return lists[id].authorizers.nonEnumerableAccounts[account];
                  }
                  function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory) {
                      return lists[collectionConfiguration[collection].listId].authorizers.enumerableAccounts.values();
                  }
                  function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool) {
                      return lists[collectionConfiguration[collection].listId].authorizers.nonEnumerableAccounts[account];
                  }
                  function _ensureCallerIsCollectionAuthorizer(address collection) internal view {
                      if (!lists[collectionConfiguration[collection].listId].authorizers.nonEnumerableAccounts[msg.sender]) {
                          revert StrictAuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();
                      }
                  }
                  /// Manage and query for operators on lists
                  function addAccountToWhitelist(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
                  }
                  function addAccountsToWhitelist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
                  }
                  function addOperators(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
                  }
                  function removeAccountFromWhitelist(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _removeAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
                  }
                  function removeAccountsFromWhitelist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _removeAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
                  }
                  
                  function getWhitelistedAccounts(uint120 id) external view returns (address[] memory) {
                      return lists[id].operators.enumerableAccounts.values();
                  }
                  function isAccountWhitelisted(uint120 id, address account) external view returns (bool) {
                      return lists[id].operators.nonEnumerableAccounts[account];
                  }
                  function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) {
                      return lists[collectionConfiguration[collection].listId].operators.enumerableAccounts.values();
                  }
                  function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool) {
                      return lists[collectionConfiguration[collection].listId].operators.nonEnumerableAccounts[account];
                  }
                  /// Manage and query for blacklists on lists
                  function addAccountToBlacklist(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _addAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
                  }
                  function addAccountsToBlacklist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _addAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
                  }
                  function removeAccountFromBlacklist(uint120 id, address account) external onlyListOwner(id) {
                      address[] memory accounts = new address[](1);
                      accounts[0] = account;
                      _removeAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
                  }
                  function removeAccountsFromBlacklist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
                      _removeAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
                  } 
                  function getBlacklistedAccounts(uint120 id) external view returns (address[] memory) {
                      return lists[id].blacklist.enumerableAccounts.values();
                  }
                  function isAccountBlacklisted(uint120 id, address account) external view returns (bool) {
                      return lists[id].blacklist.nonEnumerableAccounts[account];
                  }
                  function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory) {
                      return lists[collectionConfiguration[collection].listId].blacklist.enumerableAccounts.values();
                  }
                  function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool) {
                      return lists[collectionConfiguration[collection].listId].blacklist.nonEnumerableAccounts[account];
                  }
                  /// Ensure that a specific operator has been authorized to transfer tokens
                  function validateTransfer(address caller, address from, address to) external view {
                      _validateTransfer(caller, from, to);
                  }
                  /// Ensure that a transfer has been authorized for a specific tokenId
                  function validateTransfer(address caller, address from, address to, uint256 tokenId) external view {
                      _validateTransferByIdentifer(caller, from, to, tokenId);
                  }
                  /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
                  /// reduce the transferable amount remaining
                  function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external {
                      _validateTransferByAmount(caller, from, to, tokenId, amount);
                  }
                  /// Legacy alias for validateTransfer (address caller, address from, address to)
                  function applyCollectionTransferPolicy(address caller, address from, address to) external view {
                      _validateTransfer(caller, from, to);
                  }
                  /// Temporarily assign a specific allowed operator for a given collection
                  function beforeAuthorizedTransfer(address operator, address token) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      _setTstorish(
                          _getAuthorizedOperatorSlot(token),
                          uint256(uint160(operator))
                      );
                  }
                  /// Clear assignment of a specific allowed operator for a given collection
                  function afterAuthorizedTransfer(address token) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      _clearTstorish(_getAuthorizedOperatorSlot(token));
                  }
                  /// Temporarily allow a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransfer(address token, uint256 tokenId) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      _setTstorish(
                          _getAuthorizedIdentifierSlot(token, tokenId),
                          1
                      );
                  }
                  /// Clear assignment of an specific tokenId's transfer allowance
                  function afterAuthorizedTransfer(address token, uint256 tokenId) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      _clearTstorish(_getAuthorizedIdentifierSlot(token, tokenId));
                  }
                  /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      uint256 slot = _getAuthorizedAmountSlot(token, tokenId);
                      uint256 currentAmount = _getTstorish(slot);
                      uint256 newAmount = currentAmount + amount;
                      _setTstorish(slot, newAmount);
                  }
                  /// Clear assignment of a tokenId's transfer allowance for a specific amount
                  function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external {
                      _ensureCallerIsCollectionAuthorizer(token);
                      _clearTstorish(_getAuthorizedAmountSlot(token, tokenId));
                  }
                  function setTransferSecurityLevelOfCollection(
                      address collection,
                      uint8 level,
                      bool enableAuthorizationMode,
                      bool authorizersCanSetWildcardOperators,
                      bool enableAccountFreezingMode
                  ) external {
                      if (!enableAuthorizationMode || !authorizersCanSetWildcardOperators || enableAccountFreezingMode) {
                          revert StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevelDetail();
                      }
                      _setTransferSecurityLevelOfCollection(collection, TransferSecurityLevels(level));
                  }
                  function setTransferSecurityLevelOfCollection(
                      address collection,
                      TransferSecurityLevels level
                  ) external {
                      _setTransferSecurityLevelOfCollection(collection, level);
                  }
                  function isVerifiedEOA(address account) external view returns (bool) {
                      return _EOA_REGISTRY.isVerifiedEOA(account);
                  }
                  /// @notice ERC-165 Interface Support
                  function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) {
                      return
                          interfaceId == type(ICreatorTokenTransferValidator).interfaceId ||
                          interfaceId == type(IStrictAuthorizedTransferSecurityRegistry).interfaceId ||
                          super.supportsInterface(interfaceId);
                  }
                  function _setTransferSecurityLevelOfCollection(
                      address collection,
                      TransferSecurityLevels level
                  ) internal {
                      _requireCallerIsNFTOrContractOwnerOrAdmin(collection);
                      if (level == TransferSecurityLevels.Recommended) {
                          level = TransferSecurityLevels.Three;
                      }
                      CollectionConfiguration storage config = collectionConfiguration[collection];
                      
                      if (level == TransferSecurityLevels.One) {
                          config.policyBypassed = true;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = false;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Two) {
                          config.policyBypassed = false;
                          config.blacklistBased = true;
                          config.directTransfersDisabled = false;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Three) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = false;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Four) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = true;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Five) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = false;
                          config.contractRecipientsDisabled = true;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Six) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = false;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = true;
                      } else if (level == TransferSecurityLevels.Seven) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = true;
                          config.contractRecipientsDisabled = true;
                          config.signatureRegistrationRequired = false;
                      } else if (level == TransferSecurityLevels.Eight) {
                          config.policyBypassed = false;
                          config.blacklistBased = false;
                          config.directTransfersDisabled = true;
                          config.contractRecipientsDisabled = false;
                          config.signatureRegistrationRequired = true;
                      } else {
                          revert StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevel();
                      }
                      emit SetTransferSecurityLevel(collection, level);
                  }
                  /**
                   * @notice Copies all addresses in `ptrFromList` to `ptrToList`.
                   * 
                   * @dev    This function will copy all addresses from one list to another list.
                   * @dev    Note: If used to copy adddresses to an existing list the current list contents will not be
                   * @dev    deleted before copying. New addresses will be appeneded to the end of the list and the
                   * @dev    non-enumerable mapping key value will be set to true.
                   * 
                   * @dev <h4>Postconditions:</h4>
                   *      1. Addresses in from list that are not already present in to list are added to the to list.
                   *      2. Emits an `AddedAccountToList` event for each address copied to the list.
                   * 
                   * @param  listType          The type of list addresses are being copied from and to.
                   * @param  destinationListId The id of the list being copied to.
                   * @param  ptrFromList       The storage pointer for the list being copied from.
                   * @param  ptrToList         The storage pointer for the list being copied to.
                   */
                  function _copyAddressSet(
                      ListTypes listType,
                      uint120 destinationListId,
                      AccountList storage ptrFromList,
                      AccountList storage ptrToList
                  ) private {
                      EnumerableSet.AddressSet storage ptrFromSet = ptrFromList.enumerableAccounts;
                      EnumerableSet.AddressSet storage ptrToSet = ptrToList.enumerableAccounts;
                      mapping (address => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableAccounts;
                      uint256 sourceLength = ptrFromSet.length();
                      address account;
                      for (uint256 i = 0; i < sourceLength;) {
                          account = ptrFromSet.at(i); 
                          if (ptrToSet.add(account)) {
                              emit AddedAccountToList(listType, destinationListId, account);
                              ptrToNonEnumerableSet[account] = true;
                          }
                          unchecked {
                              ++i;
                          }
                      }
                  }
                  /**
                   * @notice Requires the caller to be the owner of list `id`.
                   * 
                   * @dev    Throws when the caller is not the owner of the list.
                   */
                  function _requireCallerOwnsList(uint120 id) private view {
                      if (msg.sender != lists[id].owner) {
                          revert StrictAuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
                      }
                  }
                  /**
                   * @notice Reverts the transaction if the caller is not the owner or assigned the default
                   * @notice admin role of the contract at `tokenAddress`.
                   *
                   * @dev    Throws when the caller is neither owner nor assigned the default admin role.
                   * 
                   * @param tokenAddress The contract address of the token to check permissions for.
                   */
                  function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view {
                      if (msg.sender == tokenAddress) {
                          return;
                      }
                      if (msg.sender == _safeOwner(tokenAddress)) {
                          return;
                      }
                      if (!_safeHasRole(tokenAddress)) {
                          revert StrictAuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
                      }
                  }
                  /**
                   * @dev A gas efficient, and fallback-safe way to call the owner function on a token contract.
                   *      This will get the owner if it exists - and when the function is unimplemented, the
                   *      presence of a fallback function will not result in halted execution.
                   */
                  function _safeOwner(
                      address tokenAddress
                  ) internal view returns(address owner) {
                      assembly {
                          mstore(0x00, 0x8da5cb5b)
                          let status := staticcall(gas(), tokenAddress, 0x1c, 0x04, 0x00, 0x20)
                          if and(iszero(lt(returndatasize(), 0x20)), status) {
                              owner := mload(0x00)
                          }
                      }
                  }
                  
                  /**
                   * @dev A gas efficient, and fallback-safe way to call the hasRole function on a token contract.
                   *      This will check if the account `hasRole` if `hasRole` exists - and when the function is unimplemented, the
                   *      presence of a fallback function will not result in halted execution.
                   */
                  function _safeHasRole(
                      address tokenAddress
                  ) internal view returns(bool hasRole) {
                      assembly {
                          let ptr := mload(0x40)
                          mstore(0x40, add(ptr, 0x60))
                          mstore(ptr, 0x91d14854)
                          mstore(add(0x20, ptr), DEFAULT_ACCESS_CONTROL_ADMIN_ROLE)
                          mstore(add(0x40, ptr), caller())
                          let status := staticcall(gas(), tokenAddress, add(ptr, 0x1c), 0x44, 0x00, 0x20)
                          if and(iszero(lt(returndatasize(), 0x20)), status) {
                              hasRole := mload(0x00)
                          }
                      }
                  }
                  /**
                   * @dev Internal function used to efficiently retrieve the code length of `account`.
                   * 
                   * @param account The address to get the deployed code length for.
                   * 
                   * @return length The length of deployed code at the address.
                   */
                  function _getCodeLengthAsm(address account) internal view returns (uint256 length) {
                      assembly { length := extcodesize(account) }
                  }
                  function _addAccounts(
                      uint120 id,
                      address[] memory accounts,
                      AccountList storage accountList,
                      ListTypes listType
                  ) internal {
                      address account;
                      for (uint256 i = 0; i < accounts.length;) {
                          account = accounts[i];
                          if (account == address(0)) {
                              revert StrictAuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed();
                          }
                          if (accountList.enumerableAccounts.add(account)) {
                              emit AddedAccountToList(listType, id, account);
                              accountList.nonEnumerableAccounts[account] = true;
                          }
                          unchecked {
                              ++i;
                          }
                      }
                  }
                  function _removeAccounts(
                      uint120 id,
                      address[] memory accounts,
                      AccountList storage accountList,
                      ListTypes listType
                  ) internal {
                      address account;
                      for (uint256 i = 0; i < accounts.length;) {
                          account = accounts[i];
                          if (accountList.enumerableAccounts.remove(account)) {
                              emit RemovedAccountFromList(listType, id, account);
                              delete accountList.nonEnumerableAccounts[account];
                          }
                          unchecked {
                              ++i;
                          }
                      }
                  }
                  function _validateTransfer(address operator, address from, address to) internal view {
                      CollectionConfiguration memory config = collectionConfiguration[msg.sender];
                      if (config.policyBypassed) {
                          return;
                      }
                      if (config.contractRecipientsDisabled) {
                          if (to.code.length != 0) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
                          }
                      }
                      
                      if (config.signatureRegistrationRequired) {
                          if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
                          }
                      }
                      if (operator == from) {
                          if (config.directTransfersDisabled) {
                              revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
                          }
                          return;
                      }
                      uint256 slot = _getAuthorizedOperatorSlot(msg.sender);
                      if (operator == address(uint160(_getTstorish(slot)))) {
                          return;
                      }
                      if (config.blacklistBased) {
                          if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      } else {
                          if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      }
                  }
                  function _validateTransferByIdentifer(address operator, address from, address to, uint256 identifier) internal view {
                      CollectionConfiguration memory config = collectionConfiguration[msg.sender];
                      if (config.policyBypassed) {
                          return;
                      }
                      if (config.contractRecipientsDisabled) {
                          if (to.code.length != 0) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
                          }
                      }
                      
                      if (config.signatureRegistrationRequired) {
                          if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
                          }
                      }
                      if (operator == from) {
                          if (config.directTransfersDisabled) {
                              revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
                          }
                          return;
                      }
                      uint256 slot = _getAuthorizedIdentifierSlot(msg.sender, identifier);
                      uint256 authorizedIdentifier = _getTstorish(slot);
                      if (authorizedIdentifier != 0) {
                          return;
                      }
                      if (config.blacklistBased) {
                          if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      } else {
                          if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      }
                  }
                  function _validateTransferByAmount(address operator, address from, address to, uint256 identifier, uint256 amount) internal {
                      CollectionConfiguration memory config = collectionConfiguration[msg.sender];
                      if (config.policyBypassed) {
                          return;
                      }
                      if (config.contractRecipientsDisabled) {
                          if (to.code.length != 0) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
                          }
                      }
                      
                      if (config.signatureRegistrationRequired) {
                          if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                              revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
                          }
                      }
                      if (operator == from) {
                          if (config.directTransfersDisabled) {
                              revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
                          }
                          return;
                      }
                      uint256 slot = _getAuthorizedAmountSlot(msg.sender, identifier);
                      uint256 authorizedAmount = _getTstorish(slot);
                      if (authorizedAmount >= amount) {
                          unchecked {
                              _setTstorish(slot, authorizedAmount - amount);
                          }
                          return;
                      }
                      if (config.blacklistBased) {
                          if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      } else {
                          if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                              revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                          }
                      }
                  }
                  function _getAuthorizedOperatorSlot(
                      address collection
                  ) internal pure returns (uint256 slot) {
                      bytes4 authorizedOperatorScope = _AUTHORIZED_OPERATOR_SCOPE;
                      assembly {
                          slot := or(
                              authorizedOperatorScope,
                              and(collection, 0xffffffffffffffffffffffffffffffffffffffff)
                          )
                      }
                  }
                  function _getAuthorizedIdentifierSlot(
                      address collection,
                      uint256 identifier
                  ) internal pure returns (uint256 slot) {
                      bytes4 authorizedIdentifierScope = _AUTHORIZED_IDENTIFIER_SCOPE;
                      assembly {
                          mstore(0x0, authorizedIdentifierScope)
                          mstore(0x18, collection)
                          mstore(0x04, identifier)
                          slot := keccak256(0x0, 0x38)
                      }
                  }
                  function _getAuthorizedAmountSlot(
                      address collection,
                      uint256 identifier
                  ) internal pure returns (uint256 slot) {
                      bytes4 authorizedAmountScope = _AUTHORIZED_AMOUNT_SCOPE;
                      assembly {
                          mstore(0x0, authorizedAmountScope)
                          mstore(0x18, collection)
                          mstore(0x04, identifier)
                          slot := keccak256(0x0, 0x38)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              enum ListTypes {
                  AuthorizerList,
                  OperatorList,
                  OperatorRequiringAuthorizationList
              }
              enum TransferSecurityLevels {
                  Recommended,
                  One,
                  Two,
                  Three,
                  Four,
                  Five,
                  Six,
                  Seven,
                  Eight
              }
              /// @title IStrictAuthorizedTransferSecurityRegistry
              /// @dev Interface for the Authorized Transfer Security Registry, a simplified version of the Transfer
              ///      Security Registry that only supports authorizers and whitelisted operators, and assumes a
              ///      security level of OperatorWhitelistEnableOTC + authorizers for all collections that use it.
              ///      Note that a number of view functions on collections that add this validator will not work.
              interface IStrictAuthorizedTransferSecurityRegistry {
                  event CreatedList(uint256 indexed id, string name);
                  event AppliedListToCollection(address indexed collection, uint120 indexed id);
                  event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
                  event AddedAccountToList(ListTypes indexed kind, uint256 indexed id, address indexed account);
                  event RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account);
                  event SetTransferSecurityLevel(address collection, TransferSecurityLevels level);
                  error StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist();
                  error StrictAuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
                  error StrictAuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
                  error StrictAuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
                  error StrictAuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
                  error StrictAuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed();
                  error StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
                  error StrictAuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();
                  error StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevel();
                  error StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevelDetail();
                  error StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
                  error StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
                  error StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
                  /// Manage lists of authorizers & operators that can be applied to collections
                  function createList(string calldata name) external returns (uint120);
                  function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120);
                  function reassignOwnershipOfList(uint120 id, address newOwner) external;
                  function renounceOwnershipOfList(uint120 id) external;
                  function applyListToCollection(address collection, uint120 id) external;
                  function listOwners(uint120 id) external view returns (address);
                  /// Manage and query for authorizers on lists
                  function addAccountToAuthorizers(uint120 id, address account) external;
                  function addAccountsToAuthorizers(uint120 id, address[] calldata accounts) external;
                  function addAuthorizers(uint120 id, address[] calldata accounts) external;
                  function removeAccountFromAuthorizers(uint120 id, address account) external;
                  
                  function removeAccountsFromAuthorizers(uint120 id, address[] calldata accounts) external;
                  function getAuthorizerAccounts(uint120 id) external view returns (address[] memory);
                  function isAccountAuthorizer(uint120 id, address account) external view returns (bool);
                  function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory);
                  function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool);
                  /// Manage and query for operators on lists
                  function addAccountToWhitelist(uint120 id, address account) external;
                  function addAccountsToWhitelist(uint120 id, address[] calldata accounts) external;
                  function addOperators(uint120 id, address[] calldata accounts) external;
                  function removeAccountFromWhitelist(uint120 id, address account) external;
                  function removeAccountsFromWhitelist(uint120 id, address[] calldata accounts) external;
                  
                  function getWhitelistedAccounts(uint120 id) external view returns (address[] memory);
                  function isAccountWhitelisted(uint120 id, address account) external view returns (bool);
                  function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory);
                  function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool);
                  /// Manage and query for blacklists on lists
                  function addAccountToBlacklist(uint120 id, address account) external;
                  function addAccountsToBlacklist(uint120 id, address[] calldata accounts) external;
                  function removeAccountFromBlacklist(uint120 id, address account) external;
                  function removeAccountsFromBlacklist(uint120 id, address[] calldata accounts) external;
                  function getBlacklistedAccounts(uint120 id) external view returns (address[] memory);
                  function isAccountBlacklisted(uint120 id, address account) external view returns (bool);
                  function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory);
                  function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool);
                  function setTransferSecurityLevelOfCollection(
                      address collection,
                      uint8 level,
                      bool enableAuthorizationMode,
                      bool authorizersCanSetWildcardOperators,
                      bool enableAccountFreezingMode
                  ) external;
                  function setTransferSecurityLevelOfCollection(
                      address collection,
                      TransferSecurityLevels level
                  ) external;
                  function isVerifiedEOA(address account) external view returns (bool);
                  /// Ensure that a specific operator has been authorized to transfer tokens
                  function validateTransfer(address caller, address from, address to) external view;
                  /// Ensure that a transfer has been authorized for a specific tokenId
                  function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
                  /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
                  /// reduce the transferable amount remaining
                  function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
                  /// Legacy alias for validateTransfer (address caller, address from, address to)
                  function applyCollectionTransferPolicy(address caller, address from, address to) external view;
                  /// Temporarily assign a specific allowed operator for a given collection
                  function beforeAuthorizedTransfer(address operator, address token) external;
                  /// Clear assignment of a specific allowed operator for a given collection
                  function afterAuthorizedTransfer(address token) external;
                  /// Temporarily allow a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
                  /// Clear assignment of an specific tokenId's transfer allowance
                  function afterAuthorizedTransfer(address token, uint256 tokenId) external;
                  /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
                  function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
                  /// Clear assignment of a tokenId's transfer allowance for a specific amount
                  function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
              }// SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              import "./IEOARegistry.sol";
              import "./ITransferSecurityRegistry.sol";
              import "./ITransferValidator.sol";
              interface ICreatorTokenTransferValidator is ITransferSecurityRegistry, ITransferValidator, IEOARegistry {}// SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              interface IOwnable {
                  function owner() external view returns (address);
              }// SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev External interface of AccessControl declared to support ERC165 detection.
               */
              interface IAccessControl {
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   *
                   * _Available since v3.1._
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call, an admin role
                   * bearer except when using {AccessControl-_setupRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) external view returns (bool);
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) external view returns (bytes32);
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) external;
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) external;
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `account`.
                   */
                  function renounceRole(bytes32 role, address account) external;
              }
              // 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
              // 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
              pragma solidity ^0.8.24;
              contract Tstorish {
                  // Declare a storage variable indicating if TSTORE support has been
                  // activated post-deployment.
                  bool private _tstoreSupport;
                  /*
                   * ------------------------------------------------------------------------+
                   * 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;
                  // Declare an immutable variable to store the tstore test contract address.
                  address private immutable _tloadTestContract;
                  // Declare an immutable variable to store the initial TSTORE support status.
                  bool private immutable _tstoreInitialSupport;
                  // Declare an immutable function type variable for the _setTstorish function
                  // based on chain support for tstore at time of deployment.
                  function(uint256,uint256) internal immutable _setTstorish;
                  // Declare an immutable function type variable for the _getTstorish function
                  // based on chain support for tstore at time of deployment.
                  function(uint256) view returns (uint256) internal immutable _getTstorish;
                  // Declare an immutable function type variable for the _clearTstorish function
                  // based on chain support for tstore at time of deployment.
                  function(uint256) internal immutable _clearTstorish;
                  // Declare a few custom revert error types.
                  error TStoreAlreadyActivated();
                  error TStoreNotSupported();
                  error TloadTestContractDeploymentFailed();
                  error OnlyDirectCalls();
                  /**
                   * @dev Determine TSTORE availability 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 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);
                      if (tstoreInitialSupport) {
                          // If TSTORE is supported, set functions to their versions that use
                          // tstore/tload directly without support checks.
                          _setTstorish = _setTstore;
                          _getTstorish = _getTstore;
                          _clearTstorish = _clearTstore;
                      } else {
                          // If TSTORE is not supported, set functions to their versions that 
                          // fallback to sstore/sload until _tstoreSupport is true.
                          _setTstorish = _setTstorishWithSstoreFallback;
                          _getTstorish = _getTstorishWithSloadFallback;
                          _clearTstorish = _clearTstorishWithSstoreFallback;
                      }
                      _tstoreInitialSupport = tstoreInitialSupport;
                      // Set the address of the deployed TLOAD test contract as an immutable.
                      _tloadTestContract = tloadTestContract;
                  }
                  /**
                   * @dev External function to activate TSTORE usage. 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 or if the
                   *      opcode is not available. Note that this must be called directly from
                   *      an externally-owned account to avoid potential reentrancy issues.
                   */
                  function __activateTstore() external {
                      // Ensure this function is triggered from an externally-owned account.
                      if (msg.sender != tx.origin) {
                          revert OnlyDirectCalls();
                      }
                      // Determine if TSTORE can potentially be activated.
                      if (_tstoreInitialSupport || _tstoreSupport) {
                          revert TStoreAlreadyActivated();
                      }
                      // Determine if TSTORE can be activated and revert if not.
                      if (!_testTload(_tloadTestContract)) {
                          revert TStoreNotSupported();
                      }
                      // Mark TSTORE as activated.
                      _tstoreSupport = true;
                  }
                  /**
                   * @dev Private function to set a TSTORISH value. Assigned to _setTstorish 
                   *      internal function variable at construction if chain has tstore support.
                   *
                   * @param storageSlot The slot to write the TSTORISH value to.
                   * @param value       The value to write to the given storage slot.
                   */
                  function _setTstore(uint256 storageSlot, uint256 value) private {
                      assembly {
                          tstore(storageSlot, value)
                      }
                  }
                  /**
                   * @dev Private function to set a TSTORISH value with sstore fallback. 
                   *      Assigned to _setTstorish internal function variable at construction
                   *      if chain does not have tstore support.
                   *
                   * @param storageSlot The slot to write the TSTORISH value to.
                   * @param value       The value to write to the given storage slot.
                   */
                  function _setTstorishWithSstoreFallback(uint256 storageSlot, uint256 value) private {
                      if (_tstoreSupport) {
                          assembly {
                              tstore(storageSlot, value)
                          }
                      } else {
                          assembly {
                              sstore(storageSlot, value)
                          }
                      }
                  }
                  /**
                   * @dev Private function to read a TSTORISH value. Assigned to _getTstorish
                   *      internal function variable at construction if chain has tstore support.
                   *
                   * @param storageSlot The slot to read the TSTORISH value from.
                   *
                   * @return value The TSTORISH value at the given storage slot.
                   */
                  function _getTstore(
                      uint256 storageSlot
                  ) private view returns (uint256 value) {
                      assembly {
                          value := tload(storageSlot)
                      }
                  }
                  /**
                   * @dev Private function to read a TSTORISH value with sload fallback. 
                   *      Assigned to _getTstorish internal function variable at construction
                   *      if chain does not have tstore support.
                   *
                   * @param storageSlot The slot to read the TSTORISH value from.
                   *
                   * @return value The TSTORISH value at the given storage slot.
                   */
                  function _getTstorishWithSloadFallback(
                      uint256 storageSlot
                  ) private view returns (uint256 value) {
                      if (_tstoreSupport) {
                          assembly {
                              value := tload(storageSlot)
                          }
                      } else {
                          assembly {
                              value := sload(storageSlot)
                          }
                      }
                  }
                  /**
                   * @dev Private function to clear a TSTORISH value. Assigned to _clearTstorish internal 
                   *      function variable at construction if chain has tstore support.
                   *
                   * @param storageSlot The slot to clear the TSTORISH value for.
                   */
                  function _clearTstore(uint256 storageSlot) private {
                      assembly {
                          tstore(storageSlot, 0)
                      }
                  }
                  /**
                   * @dev Private function to clear a TSTORISH value with sstore fallback. 
                   *      Assigned to _clearTstorish internal function variable at construction
                   *      if chain does not have tstore support.
                   *
                   * @param storageSlot The slot to clear the TSTORISH value for.
                   */
                  function _clearTstorishWithSstoreFallback(uint256 storageSlot) private {
                      if (_tstoreSupport) {
                          assembly {
                              tstore(storageSlot, 0)
                          }
                      } else {
                          assembly {
                              sstore(storageSlot, 0)
                          }
                      }
                  }
                  /**
                   * @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.4;
              import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
              interface IEOARegistry is IERC165 {
                  function isVerifiedEOA(address account) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.24;
              import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
              import { Tstorish } from "tstorish/Tstorish.sol";
              import { TransferSecurityLevels } from "./interfaces/IStrictAuthorizedTransferSecurityRegistry.sol";
              /// @title StrictAuthorizedTransferSecurityRegistryExtraViewFns
              /// @dev Additional view functions, called by StrictAuthorizedTransferSecurityRegistry
              ///      via delegatecall in the fallback.
              contract StrictAuthorizedTransferSecurityRegistryExtraViewFns is Tstorish {
                  using EnumerableSet for EnumerableSet.AddressSet;
                  error StrictAuthorizedTransferSecurityRegistry__NotImplemented();
                  struct CollectionSecurityPolicy {
                      TransferSecurityLevels transferSecurityLevel;
                      uint120 operatorWhitelistId;
                      uint120 permittedContractReceiversId;
                  }
                  struct AccountList {
                      EnumerableSet.AddressSet enumerableAccounts;
                      mapping (address => bool) nonEnumerableAccounts;
                  }
                  struct List {
                      address owner;
                      AccountList authorizers;
                      AccountList operators;
                  }
                  struct CollectionConfiguration {
                      uint120 listId;
                      bool policyBypassed;
                      bool blacklistBased;
                      bool directTransfersDisabled;
                      bool contractRecipientsDisabled;
                      bool signatureRegistrationRequired;
                  }
                  uint120 private UNUSED_lastListId;
                  mapping (uint120 => List) private lists;
                  /// @dev Mapping of collection addresses to list ids & security policies.
                  mapping (address => CollectionConfiguration) private collectionConfiguration;
                  // view functions from other transfer security registries, included for completeness
                  function getBlacklistedAccounts(uint120) external pure returns (address[] memory) {}
                  function getWhitelistedAccounts(uint120 id) external view returns (address[] memory) {
                      return lists[id].operators.enumerableAccounts.values();
                  }
                  function getBlacklistedCodeHashes(uint120) external pure returns (bytes32[] memory) {}
                  function getWhitelistedCodeHashes(uint120) external pure returns (bytes32[] memory) {}
                  function isAccountBlacklisted(uint120, address) external pure returns (bool) {
                      return false;
                  }
                  function isAccountWhitelisted(uint120 id, address account) external view returns (bool) {
                      return lists[id].operators.nonEnumerableAccounts[account];
                  }
                  function isCodeHashBlacklisted(uint120, bytes32) external pure returns (bool) {
                      return false;
                  }
                  function isCodeHashWhitelisted(uint120, bytes32) external pure returns (bool) {
                      return false;
                  }
                  function getBlacklistedAccountsByCollection(address) external pure returns (address[] memory) {}
                  function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) {
                      return lists[collectionConfiguration[collection].listId].operators.enumerableAccounts.values();
                  }
                  function getBlacklistedCodeHashesByCollection(address) external pure returns (bytes32[] memory) {}
                  function getWhitelistedCodeHashesByCollection(address) external pure returns (bytes32[] memory) {}
                  function isAccountBlacklistedByCollection(address, address) external pure returns (bool) {
                      return false;
                  }
                  function isAccountWhitelistedByCollection(
                      address collection, address account
                  ) external view returns (bool) {
                      return lists[collectionConfiguration[collection].listId].operators.nonEnumerableAccounts[account];
                  }
                  function isCodeHashBlacklistedByCollection(address, bytes32) external pure returns (bool) {
                      return false;
                  }
                  function isCodeHashWhitelistedByCollection(address, bytes32) external pure returns (bool) {
                      return false;
                  }
                  function getCollectionSecurityPolicy(
                      address collection
                  ) external view returns (CollectionSecurityPolicy memory) {
                      CollectionConfiguration memory config = collectionConfiguration[collection];
                      return CollectionSecurityPolicy({
                          transferSecurityLevel: _getSecurityLevel(config),
                          operatorWhitelistId: config.listId,
                          permittedContractReceiversId: 0
                      });
                  }
                  function getWhitelistedOperators(uint120 id) external view returns (address[] memory) {
                      return lists[id].operators.enumerableAccounts.values();
                  }
                  function getPermittedContractReceivers(uint120) external pure returns (address[] memory) {}
                  function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool) {
                      return lists[id].operators.nonEnumerableAccounts[operator];
                  }
                  function isContractReceiverPermitted(uint120, address) external pure returns (bool) {
                      return true;
                  }
                  function _getSecurityLevel(
                      CollectionConfiguration memory config
                  ) internal pure returns (TransferSecurityLevels level) {
                      bool policyBypassed = config.policyBypassed;
                      bool blacklistBased = config.blacklistBased;
                      bool directTransfersDisabled = config.directTransfersDisabled;
                      bool contractRecipientsDisabled = config.contractRecipientsDisabled;
                      bool signatureRegistrationRequired = config.signatureRegistrationRequired;
                      if (policyBypassed) {
                          return TransferSecurityLevels.One;
                      }
                      if (blacklistBased) {
                          return TransferSecurityLevels.Two;
                      }
                      if (directTransfersDisabled) {
                          if (signatureRegistrationRequired) {
                              return TransferSecurityLevels.Eight;
                          } else if (contractRecipientsDisabled) {
                              return TransferSecurityLevels.Seven;
                          }
                          return TransferSecurityLevels.Four;
                      }
                      if (signatureRegistrationRequired) {
                          return TransferSecurityLevels.Six;
                      } else if (contractRecipientsDisabled) {
                          return TransferSecurityLevels.Five;
                      }
                      return TransferSecurityLevels.Three;
                  }
                  fallback() external {
                      revert StrictAuthorizedTransferSecurityRegistry__NotImplemented();
                  }
              }// SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              import "../utils/TransferPolicy.sol";
              interface ITransferSecurityRegistry {
                  event AddedToAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
                  event CreatedAllowlist(AllowlistTypes indexed kind, uint256 indexed id, string indexed name);
                  event ReassignedAllowlistOwnership(AllowlistTypes indexed kind, uint256 indexed id, address indexed newOwner);
                  event RemovedFromAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
                  event SetAllowlist(AllowlistTypes indexed kind, address indexed collection, uint120 indexed id);
                  event SetTransferSecurityLevel(address indexed collection, TransferSecurityLevels level);
                  function createOperatorWhitelist(string calldata name) external returns (uint120);
                  function createPermittedContractReceiverAllowlist(string calldata name) external returns (uint120);
                  function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external;
                  function reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) external;
                  function renounceOwnershipOfOperatorWhitelist(uint120 id) external;
                  function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 id) external;
                  function setTransferSecurityLevelOfCollection(address collection, TransferSecurityLevels level) external;
                  function setOperatorWhitelistOfCollection(address collection, uint120 id) external;
                  function setPermittedContractReceiverAllowlistOfCollection(address collection, uint120 id) external;
                  function addOperatorToWhitelist(uint120 id, address operator) external;
                  function addPermittedContractReceiverToAllowlist(uint120 id, address receiver) external;
                  function removeOperatorFromWhitelist(uint120 id, address operator) external;
                  function removePermittedContractReceiverFromAllowlist(uint120 id, address receiver) external;
                  function getCollectionSecurityPolicy(address collection) external view returns (CollectionSecurityPolicy memory);
                  function getWhitelistedOperators(uint120 id) external view returns (address[] memory);
                  function getPermittedContractReceivers(uint120 id) external view returns (address[] memory);
                  function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool);
                  function isContractReceiverPermitted(uint120 id, address receiver) external view returns (bool);
              }// SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              import "../utils/TransferPolicy.sol";
              interface ITransferValidator {
                  function applyCollectionTransferPolicy(address caller, address from, address to) external view;
              }// 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
              pragma solidity ^0.8.4;
              /** 
               * @dev Used in events to indicate the list type that an account or 
               * @dev codehash is being added to or removed from.
               * 
               * @dev Used in Creator Token Standards V2.
               */
              enum ListTypes {
                  // 0: List type that will block a matching address/codehash that is on the list.
                  Blacklist,
                  // 1: List type that will block any matching address/codehash that is not on the list.
                  Whitelist
              }
              /** 
               * @dev Used in events to indicate the list type that event relates to.
               * 
               * @dev Used in Creator Token Standards V1.
               */
              enum AllowlistTypes {
                  // 0: List type that defines the allowed operator addresses.
                  Operators,
                  // 1: List type that defines the allowed contract receivers.
                  PermittedContractReceivers
              }
              /**
               @dev Defines the constraints that will be applied for receipt of tokens.
               */
              enum ReceiverConstraints {
                  // 0: Any address may receive tokens.
                  None,
                  // 1: Address must not have deployed bytecode.
                  NoCode,
                  // 2: Address must verify a signature with the EOA Registry to prove it is an EOA.
                  EOA
              }
              /**
               * @dev Defines the constraints that will be applied to the transfer caller.
               */
              enum CallerConstraints {
                  // 0: Any address may transfer tokens.
                  None,
                  // 1: Addresses and codehashes not on the blacklist may transfer tokens.
                  OperatorBlacklistEnableOTC,
                  // 2: Addresses and codehashes on the whitelist and the owner of the token may transfer tokens.
                  OperatorWhitelistEnableOTC,
                  // 3: Addresses and codehashes on the whitelist may transfer tokens.
                  OperatorWhitelistDisableOTC
              }
              /**
               * @dev Defines constraints for staking tokens in token wrapper contracts.
               */
              enum StakerConstraints {
                  // 0: No constraints applied to staker.
                  None,
                  // 1: Transaction originator must be the address that will receive the wrapped tokens.
                  CallerIsTxOrigin,
                  // 2: Address that will receive the wrapped tokens must be a verified EOA.
                  EOA
              }
              /**
               * @dev Used in both Creator Token Standards V1 and V2.
               * @dev Levels may have different transfer restrictions in V1 and V2. Refer to the 
               * @dev Creator Token Transfer Validator implementation for the version being utilized
               * @dev to determine the effect of the selected level.
               */
              enum TransferSecurityLevels {
                  Recommended,
                  One,
                  Two,
                  Three,
                  Four,
                  Five,
                  Six,
                  Seven,
                  Eight
              }
              /**
               * @dev Defines the caller and receiver constraints for a transfer security level.
               * @dev Used in Creator Token Standards V1.
               * 
               * @dev **callerConstraints**: The restrictions applied to the transfer caller.
               * @dev **receiverConstraints**: The restrictions applied to the transfer recipient.
               */
              struct TransferSecurityPolicy {
                  CallerConstraints callerConstraints;
                  ReceiverConstraints receiverConstraints;
              }
              /**
               * @dev Defines the security policy for a token collection in Creator Token Standards V1.
               * 
               * @dev **transferSecurityLevel**: The transfer security level set for the collection.
               * @dev **operatorWhitelistId**: The list id for the operator whitelist.
               * @dev **permittedContractReceiversId: The list id for the contracts that are allowed to receive tokens.
               */
              struct CollectionSecurityPolicy {
                  TransferSecurityLevels transferSecurityLevel;
                  uint120 operatorWhitelistId;
                  uint120 permittedContractReceiversId;
              }
              /**
               * @dev Defines the security policy for a token collection in Creator Token Standards V2.
               * 
               * @dev **transferSecurityLevel**: The transfer security level set for the collection.
               * @dev **listId**: The list id that contains the blacklist and whitelist to apply to the collection.
               */
              struct CollectionSecurityPolicyV2 {
                  TransferSecurityLevels transferSecurityLevel;
                  uint120 listId;
              }
              /** 
               * @dev Used internally in the Creator Token Base V2 contract to pack transfer validator configuration.
               * 
               * @dev **isInitialized**: If not initialized by the collection owner or admin the default validator will be used.
               * @dev **version**: The transfer validator version.
               * @dev **transferValidator**: The address of the transfer validator to use for applying collection security settings.
               */
              struct TransferValidatorReference {
                  bool isInitialized;
                  uint16 version;
                  address transferValidator;
              }

              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;
              }