ETH Price: $2,662.15 (+5.23%)

Transaction Decoder

Block:
16459082 at Jan-22-2023 01:32:47 AM +UTC
Transaction Fee:
0.002561733636104517 ETH $6.82
Gas Used:
159,241 Gas / 16.087148637 Gwei

Emitted Events:

153 NyanBall.0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62( 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62, 0x0000000000000000000000001e0049783f008a0085193e00003d00cd54003c71, 0x0000000000000000000000003991eb1498350a0e1999e239ae9a6af89b60207e, 0x000000000000000000000000c1c016d8e3b0bae39ce3e7872417f8dd6d52b0b3, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001 )
154 Seaport.OrderFulfilled( orderHash=F46E2FF3BD0E0C507683647B84F0A20FDEFAE3325D25B87FFCA9C9133DEC2026, offerer=0x3991eb1498350a0e1999e239ae9a6af89b60207e, zone=PausableZone, recipient=[Sender] 0xc1c016d8e3b0bae39ce3e7872417f8dd6d52b0b3, offer=, consideration= )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...169EdE581
(Seaport 1.1)
0x0000a26b...000fAa719
528.227126319181664191 Eth528.227548819181664191 Eth0.0004225
0x286E531F...9FFc33af5
0x3991EB14...89B60207e 0.000079247222691 Eth0.015846947222691 Eth0.0157677
(builder0x69)
2.056942438797680767 Eth2.057181300297680767 Eth0.0002388615
0xC1c016d8...d6d52B0B3
0.023685281299713615 Eth
Nonce: 20
0.004223547663609098 Eth
Nonce: 21
0.019461733636104517
0xF3fCf8BA...7831A73E3 1.761679021218435008 Eth1.762388821218435008 Eth0.0007098

Execution Trace

ETH 0.0169 Seaport.fulfillAdvancedOrder( advancedOrder=[{name:parameters, type:tuple, order:1, indexed:false, value:[{name:offerer, type:address, order:1, indexed:false, value:0x3991EB1498350a0e1999E239ae9A6aF89B60207e, valueString:0x3991EB1498350a0e1999E239ae9A6aF89B60207e}, {name:zone, type:address, order:2, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {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:3, valueString:3}, {name:startTime, type:uint256, order:6, indexed:false, value:1674350677, valueString:1674350677}, {name:endTime, type:uint256, order:7, indexed:false, value:1677029077, valueString:1677029077}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:24446860302761739304752683030156737591518664810215442929803944069480205183734, valueString:24446860302761739304752683030156737591518664810215442929803944069480205183734}, {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:0x3991EB1498350a0e1999E239ae9A6aF89B60207e, valueString:0x3991EB1498350a0e1999E239ae9A6aF89B60207e}, {name:zone, type:address, order:2, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {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:3, valueString:3}, {name:startTime, type:uint256, order:6, indexed:false, value:1674350677, valueString:1674350677}, {name:endTime, type:uint256, order:7, indexed:false, value:1677029077, valueString:1677029077}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:24446860302761739304752683030156737591518664810215442929803944069480205183734, valueString:24446860302761739304752683030156737591518664810215442929803944069480205183734}, {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:3, valueString:3}, {name:signature, type:bytes, order:4, indexed:false, value:0x68561CD5592C86E289BABA9A3CBB7F99507AC7CF2D484F2770C61954E0BF15BF49903FD4466EA17223D93281F11CB1B185CAD06EF146150B60E23C39A1B4F19D1B, valueString:0x68561CD5592C86E289BABA9A3CBB7F99507AC7CF2D484F2770C61954E0BF15BF49903FD4466EA17223D93281F11CB1B185CAD06EF146150B60E23C39A1B4F19D1B}, {name:extraData, type:bytes, order:5, indexed:false, value:0x, valueString:0x}], criteriaResolvers=, fulfillerConduitKey=0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, recipient=0x0000000000000000000000000000000000000000 ) => ( fulfilled=True )
  • PausableZone.isValidOrder( orderHash=F46E2FF3BD0E0C507683647B84F0A20FDEFAE3325D25B87FFCA9C9133DEC2026, caller=0xC1c016d8E3b0BAE39Ce3E7872417f8Dd6d52B0B3, offerer=0x3991EB1498350a0e1999E239ae9A6aF89B60207e, zoneHash=0000000000000000000000000000000000000000000000000000000000000000 )
  • ETH 0.0157677 0x3991eb1498350a0e1999e239ae9a6af89b60207e.CALL( )
  • ETH 0.0004225 PayableProxy.CALL( )
  • ETH 0.0007098 0xf3fcf8ba1bae196407bc77d8b56520f7831a73e3.CALL( )
  • Conduit.execute( transfers= ) => ( transfers= )
    • NyanBall.f242432a( )
      • ERC1155CreatorImplementation.safeTransferFrom( from=0x3991EB1498350a0e1999E239ae9A6aF89B60207e, to=0xC1c016d8E3b0BAE39Ce3E7872417f8Dd6d52B0B3, id=1, amount=1, data=0x )
        • CreatorOperatorFilterer.approveTransfer( operator=0x1E0049783F008A0085193E00003D00cd54003c71, from=0x3991EB1498350a0e1999E239ae9A6aF89B60207e, 0xC1c016d8E3b0BAE39Ce3E7872417f8Dd6d52B0B3, [1], [1] ) => ( True )
          fulfillAdvancedOrder[Consideration (ln:9159)]
          File 1 of 7: Seaport
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { Consideration } from "./lib/Consideration.sol";
          /**
           * @title Seaport
           * @custom:version 1.1
           * @author 0age (0age.eth)
           * @custom:coauthor d1ll0n (d1ll0n.eth)
           * @custom:coauthor transmissions11 (t11s.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 James Wenzel (emo.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 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 ETH/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 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.7;
          // prettier-ignore
          import {
              BasicOrderParameters,
              OrderComponents,
              Fulfillment,
              FulfillmentComponent,
              Execution,
              Order,
              AdvancedOrder,
              OrderStatus,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          /**
           * @title SeaportInterface
           * @author 0age
           * @custom:version 1.1
           * @notice Seaport is a generalized ETH/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 SeaportInterface contains all external function interfaces for Seaport.
           */
          interface SeaportInterface {
              /**
               * @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
               *                            Seaport.
               *
               * @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
               *                            Seaport.
               * @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.
               */
              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.
               */
              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 as 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).
               *
               * @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.
               */
              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.
               *
               * @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.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function matchAdvancedOrders(
                  AdvancedOrder[] calldata orders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              ) 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 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
                  );
              /**
               * @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.7;
          import "./TransferHelperStructs.sol";
          import { TokenTransferrer } from "../lib/TokenTransferrer.sol";
          import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
          // prettier-ignore
          import {
              ConduitControllerInterface
          } from "../interfaces/ConduitControllerInterface.sol";
          import { Conduit } from "../conduit/Conduit.sol";
          import { ConduitTransfer } from "../conduit/lib/ConduitStructs.sol";
          // prettier-ignore
          import {
              TransferHelperInterface
          } from "../interfaces/TransferHelperInterface.sol";
          /**
           * @title TransferHelper
           * @author stuckinaboot, stephankmin
           * @notice TransferHelper is a utility contract for transferring
           *         ERC20/ERC721/ERC1155 items in bulk to a specific recipient.
           */
          contract TransferHelper is TransferHelperInterface, TokenTransferrer {
              // Allow for interaction with the conduit controller.
              ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;
              // Cache the conduit creation hash used by the conduit controller.
              bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
              /**
               * @dev Set the supplied conduit controller and retrieve its
               *      conduit creation code hash.
               *
               *
               * @param conduitController A contract that deploys conduits, or proxies
               *                          that may optionally be used to transfer approved
               *                          ERC20/721/1155 tokens.
               */
              constructor(address conduitController) {
                  // Get the conduit creation code hash from the supplied conduit
                  // controller and set it as an immutable.
                  ConduitControllerInterface controller = ConduitControllerInterface(
                      conduitController
                  );
                  (_CONDUIT_CREATION_CODE_HASH, ) = controller.getConduitCodeHashes();
                  // Set the supplied conduit controller as an immutable.
                  _CONDUIT_CONTROLLER = controller;
              }
              /**
               * @notice Transfer multiple items to a single recipient.
               *
               * @param items      The items to transfer.
               * @param recipient  The address the items should be transferred to.
               * @param conduitKey The key of the conduit through which the bulk transfer
               *                   should occur.
               *
               * @return magicValue A value indicating that the transfers were successful.
               */
              function bulkTransfer(
                  TransferHelperItem[] calldata items,
                  address recipient,
                  bytes32 conduitKey
              ) external override returns (bytes4 magicValue) {
                  // Retrieve total number of transfers and place on stack.
                  uint256 totalTransfers = items.length;
                  // If no conduitKey is given, use TokenTransferrer to perform transfers.
                  if (conduitKey == bytes32(0)) {
                      // Skip overflow checks: all for loops are indexed starting at zero.
                      unchecked {
                          // Iterate over each transfer.
                          for (uint256 i = 0; i < totalTransfers; ++i) {
                              // Retrieve the transfer in question.
                              TransferHelperItem calldata item = items[i];
                              // Perform a transfer based on the transfer's item type.
                              // Revert if item being transferred is a native token.
                              if (item.itemType == ConduitItemType.NATIVE) {
                                  revert InvalidItemType();
                              } else if (item.itemType == ConduitItemType.ERC20) {
                                  _performERC20Transfer(
                                      item.token,
                                      msg.sender,
                                      recipient,
                                      item.amount
                                  );
                              } else if (item.itemType == ConduitItemType.ERC721) {
                                  _performERC721Transfer(
                                      item.token,
                                      msg.sender,
                                      recipient,
                                      item.identifier
                                  );
                              } else {
                                  _performERC1155Transfer(
                                      item.token,
                                      msg.sender,
                                      recipient,
                                      item.identifier,
                                      item.amount
                                  );
                              }
                          }
                      }
                  }
                  // Otherwise, a conduitKey was provided.
                  else {
                      // Derive the conduit address from the deployer, conduit key
                      // and creation code hash.
                      address conduit = address(
                          uint160(
                              uint256(
                                  keccak256(
                                      abi.encodePacked(
                                          bytes1(0xff),
                                          address(_CONDUIT_CONTROLLER),
                                          conduitKey,
                                          _CONDUIT_CREATION_CODE_HASH
                                      )
                                  )
                              )
                          )
                      );
                      // Declare a new array to populate with each token transfer.
                      ConduitTransfer[] memory conduitTransfers = new ConduitTransfer[](
                          totalTransfers
                      );
                      // Skip overflow checks: all for loops are indexed starting at zero.
                      unchecked {
                          // Iterate over each transfer.
                          for (uint256 i = 0; i < totalTransfers; ++i) {
                              // Retrieve the transfer in question.
                              TransferHelperItem calldata item = items[i];
                              // Create a ConduitTransfer corresponding to each
                              // TransferHelperItem.
                              conduitTransfers[i] = ConduitTransfer(
                                  item.itemType,
                                  item.token,
                                  msg.sender,
                                  recipient,
                                  item.identifier,
                                  item.amount
                              );
                          }
                      }
                      // Call the conduit and execute bulk transfers.
                      ConduitInterface(conduit).execute(conduitTransfers);
                  }
                  // Return a magic value indicating that the transfers were performed.
                  magicValue = this.bulkTransfer.selector;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol";
          struct TransferHelperItem {
              ConduitItemType itemType;
              address token;
              uint256 identifier;
              uint256 amount;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import "./TokenTransferrerConstants.sol";
          // prettier-ignore
          import {
              TokenTransferrerErrors
          } from "../interfaces/TokenTransferrerErrors.sol";
          import { ConduitBatch1155Transfer } from "../conduit/lib/ConduitStructs.sol";
          /**
           * @title TokenTransferrer
           * @author 0age
           * @custom:coauthor d1ll0n
           * @custom:coauthor transmissions11
           * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,
           *         ERC1155, and batch ERC1155 transfers, used by both Seaport as well as
           *         by conduits deployed by the ConduitController. Use great caution when
           *         considering these functions for use in other codebases, as there are
           *         significant side effects and edge cases that need to be thoroughly
           *         understood and carefully addressed.
           */
          contract TokenTransferrer is TokenTransferrerErrors {
              /**
               * @dev Internal function to transfer ERC20 tokens from a given originator
               *      to a given recipient. Sufficient approvals must be set on the
               *      contract performing the transfer.
               *
               * @param token      The ERC20 token to transfer.
               * @param from       The originator of the transfer.
               * @param to         The recipient of the transfer.
               * @param amount     The amount to transfer.
               */
              function _performERC20Transfer(
                  address token,
                  address from,
                  address to,
                  uint256 amount
              ) internal {
                  // Utilize assembly to perform an optimized ERC20 token transfer.
                  assembly {
                      // The free memory pointer memory slot will be used when populating
                      // call data for the transfer; read the value and restore it later.
                      let memPointer := mload(FreeMemoryPointerSlot)
                      // Write call data into memory, starting with function selector.
                      mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)
                      mstore(ERC20_transferFrom_from_ptr, from)
                      mstore(ERC20_transferFrom_to_ptr, to)
                      mstore(ERC20_transferFrom_amount_ptr, amount)
                      // Make call & copy up to 32 bytes of return data to scratch space.
                      // Scratch space does not need to be cleared ahead of time, as the
                      // subsequent check will ensure that either at least a full word of
                      // return data is received (in which case it will be overwritten) or
                      // that no data is received (in which case scratch space will be
                      // ignored) on a successful call to the given token.
                      let callStatus := call(
                          gas(),
                          token,
                          0,
                          ERC20_transferFrom_sig_ptr,
                          ERC20_transferFrom_length,
                          0,
                          OneWord
                      )
                      // Determine whether transfer was successful using status & result.
                      let success := and(
                          // Set success to whether the call reverted, if not check it
                          // either returned exactly 1 (can't just be non-zero data), or
                          // had no return data.
                          or(
                              and(eq(mload(0), 1), gt(returndatasize(), 31)),
                              iszero(returndatasize())
                          ),
                          callStatus
                      )
                      // Handle cases where either the transfer failed or no data was
                      // returned. Group these, as most transfers will succeed with data.
                      // Equivalent to `or(iszero(success), iszero(returndatasize()))`
                      // but after it's inverted for JUMPI this expression is cheaper.
                      if iszero(and(success, iszero(iszero(returndatasize())))) {
                          // If the token has no code or the transfer failed: Equivalent
                          // to `or(iszero(success), iszero(extcodesize(token)))` but
                          // after it's inverted for JUMPI this expression is cheaper.
                          if iszero(and(iszero(iszero(extcodesize(token))), success)) {
                              // If the transfer failed:
                              if iszero(success) {
                                  // If it was due to a revert:
                                  if iszero(callStatus) {
                                      // If it returned a message, bubble it up as long as
                                      // sufficient gas remains to do so:
                                      if returndatasize() {
                                          // Ensure that sufficient gas is available to
                                          // copy returndata while expanding memory where
                                          // necessary. Start by computing the word size
                                          // of returndata and allocated memory. Round up
                                          // to the nearest full word.
                                          let returnDataWords := div(
                                              add(returndatasize(), AlmostOneWord),
                                              OneWord
                                          )
                                          // Note: use the free memory pointer in place of
                                          // msize() to work around a Yul warning that
                                          // prevents accessing msize directly when the IR
                                          // pipeline is activated.
                                          let msizeWords := div(memPointer, OneWord)
                                          // Next, compute the cost of the returndatacopy.
                                          let cost := mul(CostPerWord, returnDataWords)
                                          // Then, compute cost of new memory allocation.
                                          if gt(returnDataWords, msizeWords) {
                                              cost := add(
                                                  cost,
                                                  add(
                                                      mul(
                                                          sub(
                                                              returnDataWords,
                                                              msizeWords
                                                          ),
                                                          CostPerWord
                                                      ),
                                                      div(
                                                          sub(
                                                              mul(
                                                                  returnDataWords,
                                                                  returnDataWords
                                                              ),
                                                              mul(msizeWords, msizeWords)
                                                          ),
                                                          MemoryExpansionCoefficient
                                                      )
                                                  )
                                              )
                                          }
                                          // Finally, add a small constant and compare to
                                          // gas remaining; bubble up the revert data if
                                          // enough gas is still available.
                                          if lt(add(cost, ExtraGasBuffer), gas()) {
                                              // Copy returndata to memory; overwrite
                                              // existing memory.
                                              returndatacopy(0, 0, returndatasize())
                                              // Revert, specifying memory region with
                                              // copied returndata.
                                              revert(0, returndatasize())
                                          }
                                      }
                                      // Otherwise revert with a generic error message.
                                      mstore(
                                          TokenTransferGenericFailure_error_sig_ptr,
                                          TokenTransferGenericFailure_error_signature
                                      )
                                      mstore(
                                          TokenTransferGenericFailure_error_token_ptr,
                                          token
                                      )
                                      mstore(
                                          TokenTransferGenericFailure_error_from_ptr,
                                          from
                                      )
                                      mstore(TokenTransferGenericFailure_error_to_ptr, to)
                                      mstore(TokenTransferGenericFailure_error_id_ptr, 0)
                                      mstore(
                                          TokenTransferGenericFailure_error_amount_ptr,
                                          amount
                                      )
                                      revert(
                                          TokenTransferGenericFailure_error_sig_ptr,
                                          TokenTransferGenericFailure_error_length
                                      )
                                  }
                                  // Otherwise revert with a message about the token
                                  // returning false or non-compliant return values.
                                  mstore(
                                      BadReturnValueFromERC20OnTransfer_error_sig_ptr,
                                      BadReturnValueFromERC20OnTransfer_error_signature
                                  )
                                  mstore(
                                      BadReturnValueFromERC20OnTransfer_error_token_ptr,
                                      token
                                  )
                                  mstore(
                                      BadReturnValueFromERC20OnTransfer_error_from_ptr,
                                      from
                                  )
                                  mstore(
                                      BadReturnValueFromERC20OnTransfer_error_to_ptr,
                                      to
                                  )
                                  mstore(
                                      BadReturnValueFromERC20OnTransfer_error_amount_ptr,
                                      amount
                                  )
                                  revert(
                                      BadReturnValueFromERC20OnTransfer_error_sig_ptr,
                                      BadReturnValueFromERC20OnTransfer_error_length
                                  )
                              }
                              // Otherwise, revert with error about token not having code:
                              mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                              mstore(NoContract_error_token_ptr, token)
                              revert(NoContract_error_sig_ptr, NoContract_error_length)
                          }
                          // Otherwise, the token just returned no data despite the call
                          // having succeeded; no need to optimize for this as it's not
                          // technically ERC20 compliant.
                      }
                      // Restore the original free memory pointer.
                      mstore(FreeMemoryPointerSlot, memPointer)
                      // Restore the zero slot to zero.
                      mstore(ZeroSlot, 0)
                  }
              }
              /**
               * @dev Internal function to transfer an ERC721 token from a given
               *      originator to a given recipient. Sufficient approvals must be set on
               *      the contract performing the transfer. Note that this function does
               *      not check whether the receiver can accept the ERC721 token (i.e. it
               *      does not use `safeTransferFrom`).
               *
               * @param token      The ERC721 token to transfer.
               * @param from       The originator of the transfer.
               * @param to         The recipient of the transfer.
               * @param identifier The tokenId to transfer.
               */
              function _performERC721Transfer(
                  address token,
                  address from,
                  address to,
                  uint256 identifier
              ) internal {
                  // Utilize assembly to perform an optimized ERC721 token transfer.
                  assembly {
                      // If the token has no code, revert.
                      if iszero(extcodesize(token)) {
                          mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                          mstore(NoContract_error_token_ptr, token)
                          revert(NoContract_error_sig_ptr, NoContract_error_length)
                      }
                      // The free memory pointer memory slot will be used when populating
                      // call data for the transfer; read the value and restore it later.
                      let memPointer := mload(FreeMemoryPointerSlot)
                      // Write call data to memory starting with function selector.
                      mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)
                      mstore(ERC721_transferFrom_from_ptr, from)
                      mstore(ERC721_transferFrom_to_ptr, to)
                      mstore(ERC721_transferFrom_id_ptr, identifier)
                      // Perform the call, ignoring return data.
                      let success := call(
                          gas(),
                          token,
                          0,
                          ERC721_transferFrom_sig_ptr,
                          ERC721_transferFrom_length,
                          0,
                          0
                      )
                      // If the transfer reverted:
                      if iszero(success) {
                          // If it returned a message, bubble it up as long as sufficient
                          // gas remains to do so:
                          if returndatasize() {
                              // Ensure that sufficient gas is available to copy
                              // returndata while expanding memory where necessary. Start
                              // by computing word size of returndata & allocated memory.
                              // Round up to the nearest full word.
                              let returnDataWords := div(
                                  add(returndatasize(), AlmostOneWord),
                                  OneWord
                              )
                              // Note: use the free memory pointer in place of msize() to
                              // work around a Yul warning that prevents accessing msize
                              // directly when the IR pipeline is activated.
                              let msizeWords := div(memPointer, OneWord)
                              // Next, compute the cost of the returndatacopy.
                              let cost := mul(CostPerWord, returnDataWords)
                              // Then, compute cost of new memory allocation.
                              if gt(returnDataWords, msizeWords) {
                                  cost := add(
                                      cost,
                                      add(
                                          mul(
                                              sub(returnDataWords, msizeWords),
                                              CostPerWord
                                          ),
                                          div(
                                              sub(
                                                  mul(returnDataWords, returnDataWords),
                                                  mul(msizeWords, msizeWords)
                                              ),
                                              MemoryExpansionCoefficient
                                          )
                                      )
                                  )
                              }
                              // Finally, add a small constant and compare to gas
                              // remaining; bubble up the revert data if enough gas is
                              // still available.
                              if lt(add(cost, ExtraGasBuffer), gas()) {
                                  // Copy returndata to memory; overwrite existing memory.
                                  returndatacopy(0, 0, returndatasize())
                                  // Revert, giving memory region with copied returndata.
                                  revert(0, returndatasize())
                              }
                          }
                          // Otherwise revert with a generic error message.
                          mstore(
                              TokenTransferGenericFailure_error_sig_ptr,
                              TokenTransferGenericFailure_error_signature
                          )
                          mstore(TokenTransferGenericFailure_error_token_ptr, token)
                          mstore(TokenTransferGenericFailure_error_from_ptr, from)
                          mstore(TokenTransferGenericFailure_error_to_ptr, to)
                          mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
                          mstore(TokenTransferGenericFailure_error_amount_ptr, 1)
                          revert(
                              TokenTransferGenericFailure_error_sig_ptr,
                              TokenTransferGenericFailure_error_length
                          )
                      }
                      // Restore the original free memory pointer.
                      mstore(FreeMemoryPointerSlot, memPointer)
                      // Restore the zero slot to zero.
                      mstore(ZeroSlot, 0)
                  }
              }
              /**
               * @dev Internal function to transfer ERC1155 tokens from a given
               *      originator to a given recipient. Sufficient approvals must be set on
               *      the contract performing the transfer and contract recipients must
               *      implement the ERC1155TokenReceiver interface to indicate that they
               *      are willing to accept the transfer.
               *
               * @param token      The ERC1155 token to transfer.
               * @param from       The originator of the transfer.
               * @param to         The recipient of the transfer.
               * @param identifier The id to transfer.
               * @param amount     The amount to transfer.
               */
              function _performERC1155Transfer(
                  address token,
                  address from,
                  address to,
                  uint256 identifier,
                  uint256 amount
              ) internal {
                  // Utilize assembly to perform an optimized ERC1155 token transfer.
                  assembly {
                      // If the token has no code, revert.
                      if iszero(extcodesize(token)) {
                          mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                          mstore(NoContract_error_token_ptr, token)
                          revert(NoContract_error_sig_ptr, NoContract_error_length)
                      }
                      // The following memory slots will be used when populating call data
                      // for the transfer; read the values and restore them later.
                      let memPointer := mload(FreeMemoryPointerSlot)
                      let slot0x80 := mload(Slot0x80)
                      let slot0xA0 := mload(Slot0xA0)
                      let slot0xC0 := mload(Slot0xC0)
                      // Write call data into memory, beginning with function selector.
                      mstore(
                          ERC1155_safeTransferFrom_sig_ptr,
                          ERC1155_safeTransferFrom_signature
                      )
                      mstore(ERC1155_safeTransferFrom_from_ptr, from)
                      mstore(ERC1155_safeTransferFrom_to_ptr, to)
                      mstore(ERC1155_safeTransferFrom_id_ptr, identifier)
                      mstore(ERC1155_safeTransferFrom_amount_ptr, amount)
                      mstore(
                          ERC1155_safeTransferFrom_data_offset_ptr,
                          ERC1155_safeTransferFrom_data_length_offset
                      )
                      mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)
                      // Perform the call, ignoring return data.
                      let success := call(
                          gas(),
                          token,
                          0,
                          ERC1155_safeTransferFrom_sig_ptr,
                          ERC1155_safeTransferFrom_length,
                          0,
                          0
                      )
                      // If the transfer reverted:
                      if iszero(success) {
                          // If it returned a message, bubble it up as long as sufficient
                          // gas remains to do so:
                          if returndatasize() {
                              // Ensure that sufficient gas is available to copy
                              // returndata while expanding memory where necessary. Start
                              // by computing word size of returndata & allocated memory.
                              // Round up to the nearest full word.
                              let returnDataWords := div(
                                  add(returndatasize(), AlmostOneWord),
                                  OneWord
                              )
                              // Note: use the free memory pointer in place of msize() to
                              // work around a Yul warning that prevents accessing msize
                              // directly when the IR pipeline is activated.
                              let msizeWords := div(memPointer, OneWord)
                              // Next, compute the cost of the returndatacopy.
                              let cost := mul(CostPerWord, returnDataWords)
                              // Then, compute cost of new memory allocation.
                              if gt(returnDataWords, msizeWords) {
                                  cost := add(
                                      cost,
                                      add(
                                          mul(
                                              sub(returnDataWords, msizeWords),
                                              CostPerWord
                                          ),
                                          div(
                                              sub(
                                                  mul(returnDataWords, returnDataWords),
                                                  mul(msizeWords, msizeWords)
                                              ),
                                              MemoryExpansionCoefficient
                                          )
                                      )
                                  )
                              }
                              // Finally, add a small constant and compare to gas
                              // remaining; bubble up the revert data if enough gas is
                              // still available.
                              if lt(add(cost, ExtraGasBuffer), gas()) {
                                  // Copy returndata to memory; overwrite existing memory.
                                  returndatacopy(0, 0, returndatasize())
                                  // Revert, giving memory region with copied returndata.
                                  revert(0, returndatasize())
                              }
                          }
                          // Otherwise revert with a generic error message.
                          mstore(
                              TokenTransferGenericFailure_error_sig_ptr,
                              TokenTransferGenericFailure_error_signature
                          )
                          mstore(TokenTransferGenericFailure_error_token_ptr, token)
                          mstore(TokenTransferGenericFailure_error_from_ptr, from)
                          mstore(TokenTransferGenericFailure_error_to_ptr, to)
                          mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
                          mstore(TokenTransferGenericFailure_error_amount_ptr, amount)
                          revert(
                              TokenTransferGenericFailure_error_sig_ptr,
                              TokenTransferGenericFailure_error_length
                          )
                      }
                      mstore(Slot0x80, slot0x80) // Restore slot 0x80.
                      mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.
                      mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.
                      // Restore the original free memory pointer.
                      mstore(FreeMemoryPointerSlot, memPointer)
                      // Restore the zero slot to zero.
                      mstore(ZeroSlot, 0)
                  }
              }
              /**
               * @dev Internal function to transfer ERC1155 tokens from a given
               *      originator to a given recipient. Sufficient approvals must be set on
               *      the contract performing the transfer and contract recipients must
               *      implement the ERC1155TokenReceiver interface to indicate that they
               *      are willing to accept the transfer. NOTE: this function is not
               *      memory-safe; it will overwrite existing memory, restore the free
               *      memory pointer to the default value, and overwrite the zero slot.
               *      This function should only be called once memory is no longer
               *      required and when uninitialized arrays are not utilized, and memory
               *      should be considered fully corrupted (aside from the existence of a
               *      default-value free memory pointer) after calling this function.
               *
               * @param batchTransfers The group of 1155 batch transfers to perform.
               */
              function _performERC1155BatchTransfers(
                  ConduitBatch1155Transfer[] calldata batchTransfers
              ) internal {
                  // Utilize assembly to perform optimized batch 1155 transfers.
                  assembly {
                      let len := batchTransfers.length
                      // Pointer to first head in the array, which is offset to the struct
                      // at each index. This gets incremented after each loop to avoid
                      // multiplying by 32 to get the offset for each element.
                      let nextElementHeadPtr := batchTransfers.offset
                      // Pointer to beginning of the head of the array. This is the
                      // reference position each offset references. It's held static to
                      // let each loop calculate the data position for an element.
                      let arrayHeadPtr := nextElementHeadPtr
                      // Write the function selector, which will be reused for each call:
                      // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)
                      mstore(
                          ConduitBatch1155Transfer_from_offset,
                          ERC1155_safeBatchTransferFrom_signature
                      )
                      // Iterate over each batch transfer.
                      for {
                          let i := 0
                      } lt(i, len) {
                          i := add(i, 1)
                      } {
                          // Read the offset to the beginning of the element and add
                          // it to pointer to the beginning of the array head to get
                          // the absolute position of the element in calldata.
                          let elementPtr := add(
                              arrayHeadPtr,
                              calldataload(nextElementHeadPtr)
                          )
                          // Retrieve the token from calldata.
                          let token := calldataload(elementPtr)
                          // If the token has no code, revert.
                          if iszero(extcodesize(token)) {
                              mstore(NoContract_error_sig_ptr, NoContract_error_signature)
                              mstore(NoContract_error_token_ptr, token)
                              revert(NoContract_error_sig_ptr, NoContract_error_length)
                          }
                          // Get the total number of supplied ids.
                          let idsLength := calldataload(
                              add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)
                          )
                          // Determine the expected offset for the amounts array.
                          let expectedAmountsOffset := add(
                              ConduitBatch1155Transfer_amounts_length_baseOffset,
                              mul(idsLength, OneWord)
                          )
                          // Validate struct encoding.
                          let invalidEncoding := iszero(
                              and(
                                  // ids.length == amounts.length
                                  eq(
                                      idsLength,
                                      calldataload(add(elementPtr, expectedAmountsOffset))
                                  ),
                                  and(
                                      // ids_offset == 0xa0
                                      eq(
                                          calldataload(
                                              add(
                                                  elementPtr,
                                                  ConduitBatch1155Transfer_ids_head_offset
                                              )
                                          ),
                                          ConduitBatch1155Transfer_ids_length_offset
                                      ),
                                      // amounts_offset == 0xc0 + ids.length*32
                                      eq(
                                          calldataload(
                                              add(
                                                  elementPtr,
                                                  ConduitBatchTransfer_amounts_head_offset
                                              )
                                          ),
                                          expectedAmountsOffset
                                      )
                                  )
                              )
                          )
                          // Revert with an error if the encoding is not valid.
                          if invalidEncoding {
                              mstore(
                                  Invalid1155BatchTransferEncoding_ptr,
                                  Invalid1155BatchTransferEncoding_selector
                              )
                              revert(
                                  Invalid1155BatchTransferEncoding_ptr,
                                  Invalid1155BatchTransferEncoding_length
                              )
                          }
                          // Update the offset position for the next loop
                          nextElementHeadPtr := add(nextElementHeadPtr, OneWord)
                          // Copy the first section of calldata (before dynamic values).
                          calldatacopy(
                              BatchTransfer1155Params_ptr,
                              add(elementPtr, ConduitBatch1155Transfer_from_offset),
                              ConduitBatch1155Transfer_usable_head_size
                          )
                          // Determine size of calldata required for ids and amounts. Note
                          // that the size includes both lengths as well as the data.
                          let idsAndAmountsSize := add(TwoWords, mul(idsLength, TwoWords))
                          // Update the offset for the data array in memory.
                          mstore(
                              BatchTransfer1155Params_data_head_ptr,
                              add(
                                  BatchTransfer1155Params_ids_length_offset,
                                  idsAndAmountsSize
                              )
                          )
                          // Set the length of the data array in memory to zero.
                          mstore(
                              add(
                                  BatchTransfer1155Params_data_length_basePtr,
                                  idsAndAmountsSize
                              ),
                              0
                          )
                          // Determine the total calldata size for the call to transfer.
                          let transferDataSize := add(
                              BatchTransfer1155Params_calldata_baseSize,
                              idsAndAmountsSize
                          )
                          // Copy second section of calldata (including dynamic values).
                          calldatacopy(
                              BatchTransfer1155Params_ids_length_ptr,
                              add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),
                              idsAndAmountsSize
                          )
                          // Perform the call to transfer 1155 tokens.
                          let success := call(
                              gas(),
                              token,
                              0,
                              ConduitBatch1155Transfer_from_offset, // Data portion start.
                              transferDataSize, // Location of the length of callData.
                              0,
                              0
                          )
                          // If the transfer reverted:
                          if iszero(success) {
                              // If it returned a message, bubble it up as long as
                              // sufficient gas remains to do so:
                              if returndatasize() {
                                  // Ensure that sufficient gas is available to copy
                                  // returndata while expanding memory where necessary.
                                  // Start by computing word size of returndata and
                                  // allocated memory. Round up to the nearest full word.
                                  let returnDataWords := div(
                                      add(returndatasize(), AlmostOneWord),
                                      OneWord
                                  )
                                  // Note: use transferDataSize in place of msize() to
                                  // work around a Yul warning that prevents accessing
                                  // msize directly when the IR pipeline is activated.
                                  // The free memory pointer is not used here because
                                  // this function does almost all memory management
                                  // manually and does not update it, and transferDataSize
                                  // should be the largest memory value used (unless a
                                  // previous batch was larger).
                                  let msizeWords := div(transferDataSize, OneWord)
                                  // Next, compute the cost of the returndatacopy.
                                  let cost := mul(CostPerWord, returnDataWords)
                                  // Then, compute cost of new memory allocation.
                                  if gt(returnDataWords, msizeWords) {
                                      cost := add(
                                          cost,
                                          add(
                                              mul(
                                                  sub(returnDataWords, msizeWords),
                                                  CostPerWord
                                              ),
                                              div(
                                                  sub(
                                                      mul(
                                                          returnDataWords,
                                                          returnDataWords
                                                      ),
                                                      mul(msizeWords, msizeWords)
                                                  ),
                                                  MemoryExpansionCoefficient
                                              )
                                          )
                                      )
                                  }
                                  // Finally, add a small constant and compare to gas
                                  // remaining; bubble up the revert data if enough gas is
                                  // still available.
                                  if lt(add(cost, ExtraGasBuffer), gas()) {
                                      // Copy returndata to memory; overwrite existing.
                                      returndatacopy(0, 0, returndatasize())
                                      // Revert with memory region containing returndata.
                                      revert(0, returndatasize())
                                  }
                              }
                              // Set the error signature.
                              mstore(
                                  0,
                                  ERC1155BatchTransferGenericFailure_error_signature
                              )
                              // Write the token.
                              mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)
                              // Increase the offset to ids by 32.
                              mstore(
                                  BatchTransfer1155Params_ids_head_ptr,
                                  ERC1155BatchTransferGenericFailure_ids_offset
                              )
                              // Increase the offset to amounts by 32.
                              mstore(
                                  BatchTransfer1155Params_amounts_head_ptr,
                                  add(
                                      OneWord,
                                      mload(BatchTransfer1155Params_amounts_head_ptr)
                                  )
                              )
                              // Return modified region. The total size stays the same as
                              // `token` uses the same number of bytes as `data.length`.
                              revert(0, transferDataSize)
                          }
                      }
                      // Reset the free memory pointer to the default value; memory must
                      // be assumed to be dirtied and not reused from this point forward.
                      // Also note that the zero slot is not reset to zero, meaning empty
                      // arrays cannot be safely created or utilized until it is restored.
                      mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              ConduitTransfer,
              ConduitBatch1155Transfer
          } from "../conduit/lib/ConduitStructs.sol";
          /**
           * @title ConduitInterface
           * @author 0age
           * @notice ConduitInterface contains all external function interfaces, events,
           *         and errors for conduit contracts.
           */
          interface ConduitInterface {
              /**
               * @dev Revert with an error when attempting to execute transfers using a
               *      caller that does not have an open channel.
               */
              error ChannelClosed(address channel);
              /**
               * @dev Revert with an error when attempting to update a channel to the
               *      current status of that channel.
               */
              error ChannelStatusAlreadySet(address channel, bool isOpen);
              /**
               * @dev Revert with an error when attempting to execute a transfer for an
               *      item that does not have an ERC20/721/1155 item type.
               */
              error InvalidItemType();
              /**
               * @dev Revert with an error when attempting to update the status of a
               *      channel from a caller that is not the conduit controller.
               */
              error InvalidController();
              /**
               * @dev Emit an event whenever a channel is opened or closed.
               *
               * @param channel The channel that has been updated.
               * @param open    A boolean indicating whether the conduit is open or not.
               */
              event ChannelUpdated(address indexed channel, bool open);
              /**
               * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
               *         with an open channel can call this function.
               *
               * @param transfers The ERC20/721/1155 transfers to perform.
               *
               * @return magicValue A magic value indicating that the transfers were
               *                    performed successfully.
               */
              function execute(ConduitTransfer[] calldata transfers)
                  external
                  returns (bytes4 magicValue);
              /**
               * @notice Execute a sequence of batch 1155 transfers. Only a caller with an
               *         open channel can call this function.
               *
               * @param batch1155Transfers The 1155 batch transfers to perform.
               *
               * @return magicValue A magic value indicating that the transfers were
               *                    performed successfully.
               */
              function executeBatch1155(
                  ConduitBatch1155Transfer[] calldata batch1155Transfers
              ) external returns (bytes4 magicValue);
              /**
               * @notice Execute a sequence of transfers, both single and batch 1155. Only
               *         a caller with an open channel can call this function.
               *
               * @param standardTransfers  The ERC20/721/1155 transfers to perform.
               * @param batch1155Transfers The 1155 batch transfers to perform.
               *
               * @return magicValue A magic value indicating that the transfers were
               *                    performed successfully.
               */
              function executeWithBatch1155(
                  ConduitTransfer[] calldata standardTransfers,
                  ConduitBatch1155Transfer[] calldata batch1155Transfers
              ) external returns (bytes4 magicValue);
              /**
               * @notice Open or close a given channel. Only callable by the controller.
               *
               * @param channel The channel to open or close.
               * @param isOpen  The status of the channel (either open or closed).
               */
              function updateChannel(address channel, bool isOpen) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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.7;
          import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
          import { ConduitItemType } from "./lib/ConduitEnums.sol";
          import { TokenTransferrer } from "../lib/TokenTransferrer.sol";
          // prettier-ignore
          import {
              ConduitTransfer,
              ConduitBatch1155Transfer
          } from "./lib/ConduitStructs.sol";
          import "./lib/ConduitConstants.sol";
          /**
           * @title Conduit
           * @author 0age
           * @notice This contract serves as an originator for "proxied" transfers. Each
           *         conduit is deployed and controlled by a "conduit controller" that can
           *         add and remove "channels" or contracts that can instruct the conduit
           *         to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each
           *         conduit has an owner that can arbitrarily add or remove channels, and
           *         a malicious or negligent owner can add a channel that allows for any
           *         approved ERC20/721/1155 tokens to be taken immediately — be extremely
           *         cautious with what conduits you give token approvals to!*
           */
          contract Conduit is ConduitInterface, TokenTransferrer {
              // Set deployer as an immutable controller that can update channel statuses.
              address private immutable _controller;
              // Track the status of each channel.
              mapping(address => bool) private _channels;
              /**
               * @notice Ensure that the caller is currently registered as an open channel
               *         on the conduit.
               */
              modifier onlyOpenChannel() {
                  // Utilize assembly to access channel storage mapping directly.
                  assembly {
                      // Write the caller to scratch space.
                      mstore(ChannelKey_channel_ptr, caller())
                      // Write the storage slot for _channels to scratch space.
                      mstore(ChannelKey_slot_ptr, _channels.slot)
                      // Derive the position in storage of _channels[msg.sender]
                      // and check if the stored value is zero.
                      if iszero(
                          sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))
                      ) {
                          // The caller is not an open channel; revert with
                          // ChannelClosed(caller). First, set error signature in memory.
                          mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature)
                          // Next, set the caller as the argument.
                          mstore(ChannelClosed_channel_ptr, caller())
                          // Finally, revert, returning full custom error with argument.
                          revert(ChannelClosed_error_ptr, ChannelClosed_error_length)
                      }
                  }
                  // Continue with function execution.
                  _;
              }
              /**
               * @notice In the constructor, set the deployer as the controller.
               */
              constructor() {
                  // Set the deployer as the controller.
                  _controller = msg.sender;
              }
              /**
               * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
               *         with an open channel can call this function. Note that channels
               *         are expected to implement reentrancy protection if desired, and
               *         that cross-channel reentrancy may be possible if the conduit has
               *         multiple open channels at once. Also note that channels are
               *         expected to implement checks against transferring any zero-amount
               *         items if that constraint is desired.
               *
               * @param transfers The ERC20/721/1155 transfers to perform.
               *
               * @return magicValue A magic value indicating that the transfers were
               *                    performed successfully.
               */
              function execute(ConduitTransfer[] calldata transfers)
                  external
                  override
                  onlyOpenChannel
                  returns (bytes4 magicValue)
              {
                  // Retrieve the total number of transfers and place on the stack.
                  uint256 totalStandardTransfers = transfers.length;
                  // Iterate over each transfer.
                  for (uint256 i = 0; i < totalStandardTransfers; ) {
                      // Retrieve the transfer in question and perform the transfer.
                      _transfer(transfers[i]);
                      // Skip overflow check as for loop is indexed starting at zero.
                      unchecked {
                          ++i;
                      }
                  }
                  // Return a magic value indicating that the transfers were performed.
                  magicValue = this.execute.selector;
              }
              /**
               * @notice Execute a sequence of batch 1155 item transfers. Only a caller
               *         with an open channel can call this function. Note that channels
               *         are expected to implement reentrancy protection if desired, and
               *         that cross-channel reentrancy may be possible if the conduit has
               *         multiple open channels at once. Also note that channels are
               *         expected to implement checks against transferring any zero-amount
               *         items if that constraint is desired.
               *
               * @param batchTransfers The 1155 batch item transfers to perform.
               *
               * @return magicValue A magic value indicating that the item transfers were
               *                    performed successfully.
               */
              function executeBatch1155(
                  ConduitBatch1155Transfer[] calldata batchTransfers
              ) external override onlyOpenChannel returns (bytes4 magicValue) {
                  // Perform 1155 batch transfers. Note that memory should be considered
                  // entirely corrupted from this point forward.
                  _performERC1155BatchTransfers(batchTransfers);
                  // Return a magic value indicating that the transfers were performed.
                  magicValue = this.executeBatch1155.selector;
              }
              /**
               * @notice Execute a sequence of transfers, both single ERC20/721/1155 item
               *         transfers as well as batch 1155 item transfers. Only a caller
               *         with an open channel can call this function. Note that channels
               *         are expected to implement reentrancy protection if desired, and
               *         that cross-channel reentrancy may be possible if the conduit has
               *         multiple open channels at once. Also note that channels are
               *         expected to implement checks against transferring any zero-amount
               *         items if that constraint is desired.
               *
               * @param standardTransfers The ERC20/721/1155 item transfers to perform.
               * @param batchTransfers    The 1155 batch item transfers to perform.
               *
               * @return magicValue A magic value indicating that the item transfers were
               *                    performed successfully.
               */
              function executeWithBatch1155(
                  ConduitTransfer[] calldata standardTransfers,
                  ConduitBatch1155Transfer[] calldata batchTransfers
              ) external override onlyOpenChannel returns (bytes4 magicValue) {
                  // Retrieve the total number of transfers and place on the stack.
                  uint256 totalStandardTransfers = standardTransfers.length;
                  // Iterate over each standard transfer.
                  for (uint256 i = 0; i < totalStandardTransfers; ) {
                      // Retrieve the transfer in question and perform the transfer.
                      _transfer(standardTransfers[i]);
                      // Skip overflow check as for loop is indexed starting at zero.
                      unchecked {
                          ++i;
                      }
                  }
                  // Perform 1155 batch transfers. Note that memory should be considered
                  // entirely corrupted from this point forward aside from the free memory
                  // pointer having the default value.
                  _performERC1155BatchTransfers(batchTransfers);
                  // Return a magic value indicating that the transfers were performed.
                  magicValue = this.executeWithBatch1155.selector;
              }
              /**
               * @notice Open or close a given channel. Only callable by the controller.
               *
               * @param channel The channel to open or close.
               * @param isOpen  The status of the channel (either open or closed).
               */
              function updateChannel(address channel, bool isOpen) external override {
                  // Ensure that the caller is the controller of this contract.
                  if (msg.sender != _controller) {
                      revert InvalidController();
                  }
                  // Ensure that the channel does not already have the indicated status.
                  if (_channels[channel] == isOpen) {
                      revert ChannelStatusAlreadySet(channel, isOpen);
                  }
                  // Update the status of the channel.
                  _channels[channel] = isOpen;
                  // Emit a corresponding event.
                  emit ChannelUpdated(channel, isOpen);
              }
              /**
               * @dev Internal function to transfer a given ERC20/721/1155 item. Note that
               *      channels are expected to implement checks against transferring any
               *      zero-amount items if that constraint is desired.
               *
               * @param item The ERC20/721/1155 item to transfer.
               */
              function _transfer(ConduitTransfer calldata item) internal {
                  // Determine the transfer method based on the respective item type.
                  if (item.itemType == ConduitItemType.ERC20) {
                      // Transfer ERC20 token. Note that item.identifier is ignored and
                      // therefore ERC20 transfer items are potentially malleable — this
                      // check should be performed by the calling channel if a constraint
                      // on item malleability is desired.
                      _performERC20Transfer(item.token, item.from, item.to, item.amount);
                  } else if (item.itemType == ConduitItemType.ERC721) {
                      // Ensure that exactly one 721 item is being transferred.
                      if (item.amount != 1) {
                          revert InvalidERC721TransferAmount();
                      }
                      // Transfer ERC721 token.
                      _performERC721Transfer(
                          item.token,
                          item.from,
                          item.to,
                          item.identifier
                      );
                  } else if (item.itemType == ConduitItemType.ERC1155) {
                      // Transfer ERC1155 token.
                      _performERC1155Transfer(
                          item.token,
                          item.from,
                          item.to,
                          item.identifier,
                          item.amount
                      );
                  } else {
                      // Throw with an error.
                      revert InvalidItemType();
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { ConduitItemType } from "./ConduitEnums.sol";
          struct ConduitTransfer {
              ConduitItemType itemType;
              address token;
              address from;
              address to;
              uint256 identifier;
              uint256 amount;
          }
          struct ConduitBatch1155Transfer {
              address token;
              address from;
              address to;
              uint256[] ids;
              uint256[] amounts;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { TransferHelperItem } from "../helpers/TransferHelperStructs.sol";
          interface TransferHelperInterface {
              /**
               * @dev Revert with an error when attempting to execute transfers with a
               *      NATIVE itemType.
               */
              error InvalidItemType();
              /**
               * @notice Transfer multiple items to a single recipient.
               *
               * @param items The items to transfer.
               * @param recipient  The address the items should be transferred to.
               * @param conduitKey  The key of the conduit performing the bulk transfer.
               */
              function bulkTransfer(
                  TransferHelperItem[] calldata items,
                  address recipient,
                  bytes32 conduitKey
              ) external returns (bytes4);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          enum ConduitItemType {
              NATIVE, // unused
              ERC20,
              ERC721,
              ERC1155
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /*
           * -------------------------- Disambiguation & Other Notes ---------------------
           *    - The term "head" is used as it is in the documentation for ABI encoding,
           *      but only in reference to dynamic types, i.e. it always refers to the
           *      offset or pointer to the body of a dynamic type. In calldata, the head
           *      is always an offset (relative to the parent object), while in memory,
           *      the head is always the pointer to the body. More information found here:
           *      https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding
           *        - Note that the length of an array is separate from and precedes the
           *          head of the array.
           *
           *    - The term "body" is used in place of the term "head" used in the ABI
           *      documentation. It refers to the start of the data for a dynamic type,
           *      e.g. the first word of a struct or the first word of the first element
           *      in an array.
           *
           *    - The term "pointer" is used to describe the absolute position of a value
           *      and never an offset relative to another value.
           *        - The suffix "_ptr" refers to a memory pointer.
           *        - The suffix "_cdPtr" refers to a calldata pointer.
           *
           *    - The term "offset" is used to describe the position of a value relative
           *      to some parent value. For example, OrderParameters_conduit_offset is the
           *      offset to the "conduit" value in the OrderParameters struct relative to
           *      the start of the body.
           *        - Note: Offsets are used to derive pointers.
           *
           *    - Some structs have pointers defined for all of their fields in this file.
           *      Lines which are commented out are fields that are not used in the
           *      codebase but have been left in for readability.
           */
          uint256 constant AlmostOneWord = 0x1f;
          uint256 constant OneWord = 0x20;
          uint256 constant TwoWords = 0x40;
          uint256 constant ThreeWords = 0x60;
          uint256 constant FreeMemoryPointerSlot = 0x40;
          uint256 constant ZeroSlot = 0x60;
          uint256 constant DefaultFreeMemoryPointer = 0x80;
          uint256 constant Slot0x80 = 0x80;
          uint256 constant Slot0xA0 = 0xa0;
          uint256 constant Slot0xC0 = 0xc0;
          // abi.encodeWithSignature("transferFrom(address,address,uint256)")
          uint256 constant ERC20_transferFrom_signature = (
              0x23b872dd00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ERC20_transferFrom_sig_ptr = 0x0;
          uint256 constant ERC20_transferFrom_from_ptr = 0x04;
          uint256 constant ERC20_transferFrom_to_ptr = 0x24;
          uint256 constant ERC20_transferFrom_amount_ptr = 0x44;
          uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
          // abi.encodeWithSignature(
          //     "safeTransferFrom(address,address,uint256,uint256,bytes)"
          // )
          uint256 constant ERC1155_safeTransferFrom_signature = (
              0xf242432a00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;
          uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;
          uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;
          uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;
          uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;
          uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;
          uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;
          uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196
          uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;
          // abi.encodeWithSignature(
          //     "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
          // )
          uint256 constant ERC1155_safeBatchTransferFrom_signature = (
              0x2eb2c2d600000000000000000000000000000000000000000000000000000000
          );
          bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(
              bytes32(ERC1155_safeBatchTransferFrom_signature)
          );
          uint256 constant ERC721_transferFrom_signature = ERC20_transferFrom_signature;
          uint256 constant ERC721_transferFrom_sig_ptr = 0x0;
          uint256 constant ERC721_transferFrom_from_ptr = 0x04;
          uint256 constant ERC721_transferFrom_to_ptr = 0x24;
          uint256 constant ERC721_transferFrom_id_ptr = 0x44;
          uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
          // abi.encodeWithSignature("NoContract(address)")
          uint256 constant NoContract_error_signature = (
              0x5f15d67200000000000000000000000000000000000000000000000000000000
          );
          uint256 constant NoContract_error_sig_ptr = 0x0;
          uint256 constant NoContract_error_token_ptr = 0x4;
          uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36
          // abi.encodeWithSignature(
          //     "TokenTransferGenericFailure(address,address,address,uint256,uint256)"
          // )
          uint256 constant TokenTransferGenericFailure_error_signature = (
              0xf486bc8700000000000000000000000000000000000000000000000000000000
          );
          uint256 constant TokenTransferGenericFailure_error_sig_ptr = 0x0;
          uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x4;
          uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x24;
          uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x44;
          uint256 constant TokenTransferGenericFailure_error_id_ptr = 0x64;
          uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0x84;
          // 4 + 32 * 5 == 164
          uint256 constant TokenTransferGenericFailure_error_length = 0xa4;
          // abi.encodeWithSignature(
          //     "BadReturnValueFromERC20OnTransfer(address,address,address,uint256)"
          // )
          uint256 constant BadReturnValueFromERC20OnTransfer_error_signature = (
              0x9889192300000000000000000000000000000000000000000000000000000000
          );
          uint256 constant BadReturnValueFromERC20OnTransfer_error_sig_ptr = 0x0;
          uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x4;
          uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x24;
          uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x44;
          uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x64;
          // 4 + 32 * 4 == 132
          uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
          uint256 constant ExtraGasBuffer = 0x20;
          uint256 constant CostPerWord = 3;
          uint256 constant MemoryExpansionCoefficient = 0x200;
          // Values are offset by 32 bytes in order to write the token to the beginning
          // in the event of a revert
          uint256 constant BatchTransfer1155Params_ptr = 0x24;
          uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;
          uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;
          uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;
          uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;
          uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;
          uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;
          uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;
          uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;
          uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;
          uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;
          uint256 constant ConduitBatch1155Transfer_from_offset = 0x20;
          uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;
          uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;
          uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;
          uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;
          uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;
          // Note: abbreviated version of above constant to adhere to line length limit.
          uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;
          uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;
          uint256 constant Invalid1155BatchTransferEncoding_length = 0x04;
          uint256 constant Invalid1155BatchTransferEncoding_selector = (
              0xeba2084c00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ERC1155BatchTransferGenericFailure_error_signature = (
              0xafc445e200000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;
          uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @title TokenTransferrerErrors
           */
          interface TokenTransferrerErrors {
              /**
               * @dev Revert with an error when an ERC721 transfer with amount other than
               *      one is attempted.
               */
              error InvalidERC721TransferAmount();
              /**
               * @dev Revert with an error when attempting to fulfill an order where an
               *      item has an amount of zero.
               */
              error MissingItemAmount();
              /**
               * @dev Revert with an error when attempting to fulfill an order where an
               *      item has unused parameters. This includes both the token and the
               *      identifier parameters for native transfers as well as the identifier
               *      parameter for ERC20 transfers. Note that the conduit does not
               *      perform this check, leaving it up to the calling channel to enforce
               *      when desired.
               */
              error UnusedItemParameters();
              /**
               * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token
               *      transfer reverts.
               *
               * @param token      The token for which the transfer was attempted.
               * @param from       The source of the attempted transfer.
               * @param to         The recipient of the attempted transfer.
               * @param identifier The identifier for the attempted transfer.
               * @param amount     The amount for the attempted transfer.
               */
              error TokenTransferGenericFailure(
                  address token,
                  address from,
                  address to,
                  uint256 identifier,
                  uint256 amount
              );
              /**
               * @dev Revert with an error when a batch ERC1155 token transfer reverts.
               *
               * @param token       The token for which the transfer was attempted.
               * @param from        The source of the attempted transfer.
               * @param to          The recipient of the attempted transfer.
               * @param identifiers The identifiers for the attempted transfer.
               * @param amounts     The amounts for the attempted transfer.
               */
              error ERC1155BatchTransferGenericFailure(
                  address token,
                  address from,
                  address to,
                  uint256[] identifiers,
                  uint256[] amounts
              );
              /**
               * @dev Revert with an error when an ERC20 token transfer returns a falsey
               *      value.
               *
               * @param token      The token for which the ERC20 transfer was attempted.
               * @param from       The source of the attempted ERC20 transfer.
               * @param to         The recipient of the attempted ERC20 transfer.
               * @param amount     The amount for the attempted ERC20 transfer.
               */
              error BadReturnValueFromERC20OnTransfer(
                  address token,
                  address from,
                  address to,
                  uint256 amount
              );
              /**
               * @dev Revert with an error when an account being called as an assumed
               *      contract does not have code and returns no data.
               *
               * @param account The account that should contain code.
               */
              error NoContract(address account);
              /**
               * @dev Revert with an error when attempting to execute an 1155 batch
               *      transfer using calldata not produced by default ABI encoding or with
               *      different lengths for ids and amounts arrays.
               */
              error Invalid1155BatchTransferEncoding();
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // error ChannelClosed(address channel)
          uint256 constant ChannelClosed_error_signature = (
              0x93daadf200000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ChannelClosed_error_ptr = 0x00;
          uint256 constant ChannelClosed_channel_ptr = 0x4;
          uint256 constant ChannelClosed_error_length = 0x24;
          // For the mapping:
          // mapping(address => bool) channels
          // The position in storage for a particular account is:
          // keccak256(abi.encode(account, channels.slot))
          uint256 constant ChannelKey_channel_ptr = 0x00;
          uint256 constant ChannelKey_slot_ptr = 0x20;
          uint256 constant ChannelKey_length = 0x40;
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
          import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol";
          import { ItemType } from "./ConsiderationEnums.sol";
          import { ReceivedItem } from "./ConsiderationStructs.sol";
          import { Verifiers } from "./Verifiers.sol";
          import { TokenTransferrer } from "./TokenTransferrer.sol";
          import "./ConsiderationConstants.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) {
                          revert UnusedItemParameters();
                      }
                      // transfer the native tokens to the recipient.
                      _transferEth(item.recipient, item.amount);
                  } else if (item.itemType == ItemType.ERC20) {
                      // Ensure that no identifier is supplied.
                      if (item.identifier != 0) {
                          revert UnusedItemParameters();
                      }
                      // 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 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 itself.
               *
               * @param itemType   The type of item to transfer, either ERC721 or ERC1155.
               * @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.
               * @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,
                  address token,
                  address from,
                  address to,
                  uint256 identifier,
                  uint256 amount,
                  bytes32 conduitKey
              ) internal {
                  // Determine if the transfer is to be performed via a conduit.
                  if (conduitKey != bytes32(0)) {
                      // 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 to memory.
                          mstore(add(callDataOffset, Conduit_execute_transferTo_ptr), to)
                          // 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) {
                              revert InvalidERC721TransferAmount();
                          }
                          // Perform transfer via the token contract directly.
                          _performERC721Transfer(token, from, to, identifier);
                      } else {
                          // Perform transfer via the token contract directly.
                          _performERC1155Transfer(token, from, to, identifier, amount);
                      }
                  }
              }
              /**
               * @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 _transferEth(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 ETH 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.
                      revert EtherTransferGenericFailure(to, amount);
                  }
              }
              /**
               * @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 (must be 1 for ERC721).
               * @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 _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) {
                          revert InvalidERC721TransferAmount();
                      }
                      // 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.
                      revert InvalidCallToConduit(conduit);
                  }
                  // Ensure result was extracted and matches EIP-1271 magic value.
                  if (result != ConduitInterface.execute.selector) {
                      revert InvalidConduit(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.7;
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          enum Side {
              // 0: Items that can be spent
              OFFER,
              // 1: Items that must be received
              CONSIDERATION
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              OrderType,
              BasicOrderType,
              ItemType,
              Side
          } from "./ConsiderationEnums.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 included in a staticcall to
           *      `isValidOrderIncludingExtraData` on the zone for the order if the order
           *      type is restricted and the offerer or zone are not the caller.
           */
          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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { OrderStatus } from "./ConsiderationStructs.sol";
          import { Assertions } from "./Assertions.sol";
          import { SignatureVerification } from "./SignatureVerification.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) {
                  // Revert if order's timespan hasn't started yet or has already ended.
                  if (startTime > block.timestamp || endTime <= block.timestamp) {
                      // Only revert if revertOnInvalid has been supplied as true.
                      if (revertOnInvalid) {
                          revert InvalidTime();
                      }
                      // Return false as the order is invalid.
                      return false;
                  }
                  // Return true as the order time is valid.
                  valid = true;
              }
              /**
               * @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 32 or 33 bytes or if the recovered signer does not match the
               *      supplied offerer. Note that in cases where a 32 or 33 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 {
                  // Skip signature verification if the offerer is the caller.
                  if (offerer == msg.sender) {
                      return;
                  }
                  // Derive EIP-712 digest using the domain separator and the order hash.
                  bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash);
                  // Ensure that the signature for the digest is valid for the offerer.
                  _assertValidSignature(offerer, digest, signature);
              }
              /**
               * @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) {
                          revert OrderIsCancelled(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.
                          revert OrderPartiallyFilled(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) {
                              revert OrderAlreadyFilled(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.7;
          /*
           * -------------------------- Disambiguation & Other Notes ---------------------
           *    - The term "head" is used as it is in the documentation for ABI encoding,
           *      but only in reference to dynamic types, i.e. it always refers to the
           *      offset or pointer to the body of a dynamic type. In calldata, the head
           *      is always an offset (relative to the parent object), while in memory,
           *      the head is always the pointer to the body. More information found here:
           *      https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding
           *        - Note that the length of an array is separate from and precedes the
           *          head of the array.
           *
           *    - The term "body" is used in place of the term "head" used in the ABI
           *      documentation. It refers to the start of the data for a dynamic type,
           *      e.g. the first word of a struct or the first word of the first element
           *      in an array.
           *
           *    - The term "pointer" is used to describe the absolute position of a value
           *      and never an offset relative to another value.
           *        - The suffix "_ptr" refers to a memory pointer.
           *        - The suffix "_cdPtr" refers to a calldata pointer.
           *
           *    - The term "offset" is used to describe the position of a value relative
           *      to some parent value. For example, OrderParameters_conduit_offset is the
           *      offset to the "conduit" value in the OrderParameters struct relative to
           *      the start of the body.
           *        - Note: Offsets are used to derive pointers.
           *
           *    - Some structs have pointers defined for all of their fields in this file.
           *      Lines which are commented out are fields that are not used in the
           *      codebase but have been left in for readability.
           */
          // 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 = 77;
          uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;
          uint256 constant Version = 0x312e31;
          uint256 constant Version_length = 3;
          uint256 constant Version_shift = 0xe8;
          uint256 constant _NOT_ENTERED = 1;
          uint256 constant _ENTERED = 2;
          // Common Offsets
          // Offsets for identically positioned fields shared by:
          // OfferItem, ConsiderationItem, SpentItem, ReceivedItem
          uint256 constant Common_token_offset = 0x20;
          uint256 constant Common_identifier_offset = 0x40;
          uint256 constant Common_amount_offset = 0x60;
          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_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 InvalidFulfillmentComponentData_error_signature = (
              0x7fda727900000000000000000000000000000000000000000000000000000000
          );
          uint256 constant InvalidFulfillmentComponentData_error_len = 0x04;
          uint256 constant Panic_error_signature = (
              0x4e487b7100000000000000000000000000000000000000000000000000000000
          );
          uint256 constant Panic_error_offset = 0x04;
          uint256 constant Panic_error_length = 0x24;
          uint256 constant Panic_arithmetic = 0x11;
          uint256 constant MissingItemAmount_error_signature = (
              0x91b3e51400000000000000000000000000000000000000000000000000000000
          );
          uint256 constant MissingItemAmount_error_len = 0x04;
          uint256 constant OrderParameters_offer_head_offset = 0x40;
          uint256 constant OrderParameters_consideration_head_offset = 0x60;
          uint256 constant OrderParameters_conduit_offset = 0x120;
          uint256 constant OrderParameters_counter_offset = 0x140;
          uint256 constant Fulfillment_itemIndex_offset = 0x20;
          uint256 constant AdvancedOrder_numerator_offset = 0x20;
          uint256 constant AlmostOneWord = 0x1f;
          uint256 constant OneWord = 0x20;
          uint256 constant TwoWords = 0x40;
          uint256 constant ThreeWords = 0x60;
          uint256 constant FourWords = 0x80;
          uint256 constant FiveWords = 0xa0;
          uint256 constant FreeMemoryPointerSlot = 0x40;
          uint256 constant ZeroSlot = 0x60;
          uint256 constant DefaultFreeMemoryPointer = 0x80;
          uint256 constant Slot0x80 = 0x80;
          uint256 constant Slot0xA0 = 0xa0;
          uint256 constant BasicOrder_endAmount_cdPtr = 0x104;
          uint256 constant BasicOrder_common_params_size = 0xa0;
          uint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;
          uint256 constant EIP712_Order_size = 0x180;
          uint256 constant EIP712_OfferItem_size = 0xc0;
          uint256 constant EIP712_ConsiderationItem_size = 0xe0;
          uint256 constant AdditionalRecipients_size = 0x40;
          uint256 constant EIP712_DomainSeparator_offset = 0x02;
          uint256 constant EIP712_OrderHash_offset = 0x22;
          uint256 constant EIP712_DigestPayload_size = 0x42;
          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_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;
          // 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_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_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 = DefaultFreeMemoryPointer;
          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;
          // 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_signatureHead_negativeOffset = 0x20;
          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;
          // abi.encodeWithSignature("NoContract(address)")
          uint256 constant NoContract_error_signature = (
              0x5f15d67200000000000000000000000000000000000000000000000000000000
          );
          uint256 constant NoContract_error_sig_ptr = 0x0;
          uint256 constant NoContract_error_token_ptr = 0x4;
          uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36
          uint256 constant EIP_712_PREFIX = (
              0x1901000000000000000000000000000000000000000000000000000000000000
          );
          uint256 constant ExtraGasBuffer = 0x20;
          uint256 constant CostPerWord = 3;
          uint256 constant MemoryExpansionCoefficient = 0x200; // 512
          uint256 constant Create2AddressDerivation_ptr = 0x0b;
          uint256 constant Create2AddressDerivation_length = 0x55;
          uint256 constant MaskOverByteTwelve = (
              0x0000000000000000000000ff0000000000000000000000000000000000000000
          );
          uint256 constant MaskOverLastTwentyBytes = (
              0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
          );
          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;
          // Declare constant for errors related to amount derivation.
          // error InexactFraction() @ AmountDerivationErrors.sol
          uint256 constant InexactFraction_error_signature = (
              0xc63cf08900000000000000000000000000000000000000000000000000000000
          );
          uint256 constant InexactFraction_error_len = 0x04;
          // Declare constant for errors related to signature verification.
          uint256 constant Ecrecover_precompile = 1;
          uint256 constant Ecrecover_args_size = 0x80;
          uint256 constant Signature_lower_v = 27;
          // error BadSignatureV(uint8) @ SignatureVerificationErrors.sol
          uint256 constant BadSignatureV_error_signature = (
              0x1f003d0a00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant BadSignatureV_error_offset = 0x04;
          uint256 constant BadSignatureV_error_length = 0x24;
          // error InvalidSigner() @ SignatureVerificationErrors.sol
          uint256 constant InvalidSigner_error_signature = (
              0x815e1d6400000000000000000000000000000000000000000000000000000000
          );
          uint256 constant InvalidSigner_error_length = 0x04;
          // error InvalidSignature() @ SignatureVerificationErrors.sol
          uint256 constant InvalidSignature_error_signature = (
              0x8baa579f00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant InvalidSignature_error_length = 0x04;
          // error BadContractSignature() @ SignatureVerificationErrors.sol
          uint256 constant BadContractSignature_error_signature = (
              0x4f7fb80d00000000000000000000000000000000000000000000000000000000
          );
          uint256 constant BadContractSignature_error_length = 0x04;
          uint256 constant NumBitsAfterSelector = 0xe0;
          // 69 is the lowest modulus for which the remainder
          // of every selector other than the two match functions
          // is greater than those of the match functions.
          uint256 constant NonMatchSelector_MagicModulus = 69;
          // Of the two match function selectors, the highest
          // remainder modulo 69 is 29.
          uint256 constant NonMatchSelector_MagicRemainder = 0x1d;
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { OrderParameters } from "./ConsiderationStructs.sol";
          import { GettersAndDerivers } from "./GettersAndDerivers.sol";
          // prettier-ignore
          import {
              TokenTransferrerErrors
          } from "../interfaces/TokenTransferrerErrors.sol";
          import { CounterManager } from "./CounterManager.sol";
          import "./ConsiderationConstants.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) {
                      revert MissingOriginalConsiderationItems();
                  }
              }
              /**
               * @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 {
                  // Revert if the supplied amount is equal to zero.
                  if (amount == 0) {
                      revert MissingItemAmount();
                  }
              }
              /**
               * @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)
                       */
                      validOffsets := and(
                          // Order parameters at calldata 0x04 must have offset of 0x20.
                          eq(
                              calldataload(BasicOrder_parameters_cdPtr),
                              BasicOrder_parameters_ptr
                          ),
                          // Additional recipients at cd 0x224 must have offset of 0x240.
                          eq(
                              calldataload(BasicOrder_additionalRecipients_head_cdPtr),
                              BasicOrder_additionalRecipients_head_ptr
                          )
                      )
                      validOffsets := and(
                          validOffsets,
                          eq(
                              // Load signature offset from calldata 0x244.
                              calldataload(BasicOrder_signature_cdPtr),
                              // Derive expected offset as start of recipients + len * 64.
                              add(
                                  BasicOrder_signature_ptr,
                                  mul(
                                      // Additional recipients length at calldata 0x264.
                                      calldataload(
                                          BasicOrder_additionalRecipients_length_cdPtr
                                      ),
                                      // Each additional recipient has a length of 0x40.
                                      AdditionalRecipients_size
                                  )
                              )
                          )
                      )
                      validOffsets := and(
                          validOffsets,
                          lt(
                              // BasicOrderType parameter at calldata offset 0x124.
                              calldataload(BasicOrder_basicOrderType_cdPtr),
                              // Value should be less than 24.
                              BasicOrder_basicOrderType_range
                          )
                      )
                  }
                  // Revert with an error if basic order parameter offsets are invalid.
                  if (!validOffsets) {
                      revert InvalidBasicOrderParameterEncoding();
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { EIP1271Interface } from "../interfaces/EIP1271Interface.sol";
          // prettier-ignore
          import {
              SignatureVerificationErrors
          } from "../interfaces/SignatureVerificationErrors.sol";
          import { LowLevelHelpers } from "./LowLevelHelpers.sol";
          import "./ConsiderationConstants.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 the signature against.
               * @param signature A signature from the signer indicating that the order
               *                  has been approved.
               */
              function _assertValidSignature(
                  address signer,
                  bytes32 digest,
                  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)
                      // 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)
                          // 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.
                              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) {
                          // 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)
                          // Get pointer to use for `digest` input to `isValidSignature`.
                          let digestPtr := sub(
                              signature,
                              EIP1271_isValidSignature_digest_negativeOffset
                          )
                          // Cache the value currently stored at the digest pointer.
                          let cachedWordOverwrittenByDigest := mload(digestPtr)
                          // Write the selector first, since it overlaps the digest.
                          mstore(selectorPtr, EIP1271_isValidSignature_selector)
                          // Next, write the digest.
                          mstore(digestPtr, digest)
                          // Call signer with `isValidSignature` to validate signature.
                          success := staticcall(
                              gas(),
                              signer,
                              selectorPtr,
                              add(
                                  signatureLength,
                                  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.
                                      mstore(0, BadContractSignature_error_signature)
                                      revert(0, BadContractSignature_error_length)
                                  }
                                  // Check if signature length was invalid.
                                  if gt(sub(ECDSA_MaxLength, signatureLength), 1) {
                                      // Revert with generic invalid signature error.
                                      mstore(0, InvalidSignature_error_signature)
                                      revert(0, InvalidSignature_error_length)
                                  }
                                  // Check if v was invalid.
                                  if iszero(
                                      byte(v, ECDSA_twentySeventhAndTwentyEighthBytesSet)
                                  ) {
                                      // Revert with invalid v value.
                                      mstore(0, BadSignatureV_error_signature)
                                      mstore(BadSignatureV_error_offset, v)
                                      revert(0, BadSignatureV_error_length)
                                  }
                                  // Revert with generic invalid signer error message.
                                  mstore(0, InvalidSigner_error_signature)
                                  revert(0, InvalidSigner_error_length)
                              }
                          }
                          // Restore the cached values overwritten by selector, digest and
                          // signature head.
                          mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                          mstore(selectorPtr, cachedWordOverwrittenBySelector)
                          mstore(digestPtr, 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 {
                          mstore(0, BadContractSignature_error_signature)
                          revert(0, BadContractSignature_error_length)
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { OrderParameters } from "./ConsiderationStructs.sol";
          import { ConsiderationBase } from "./ConsiderationBase.sol";
          import "./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.
                      // prettier-ignore
                      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),
                          mul(offerLength, OneWord)
                      )
                  }
                  // 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).
                      // prettier-ignore
                      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),
                          mul(originalConsiderationLength, OneWord)
                      )
                  }
                  // 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) {
                  // prettier-ignore
                  return block.chainid == _CHAIN_ID
                      ? _DOMAIN_SEPARATOR
                      : _deriveDomainSeparator();
              }
              /**
               * @dev Internal view function to 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()
                  internal
                  view
                  returns (
                      string memory version,
                      bytes32 domainSeparator,
                      address conduitController
                  )
              {
                  // Derive the domain separator.
                  domainSeparator = _domainSeparator();
                  // Declare variable as immutables cannot be accessed within assembly.
                  conduitController = address(_CONDUIT_CONTROLLER);
                  // Allocate a string with the intended length.
                  version = new string(Version_length);
                  // Set the version as data on the newly allocated string.
                  assembly {
                      mstore(add(version, OneWord), shl(Version_shift, Version))
                  }
              }
              /**
               * @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.13;
          // prettier-ignore
          import {
              ConsiderationEventsAndErrors
          } from "../interfaces/ConsiderationEventsAndErrors.sol";
          import { ReentrancyGuard } from "./ReentrancyGuard.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 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() internal returns (uint256 newCounter) {
                  // Ensure that the reentrancy guard is not currently set.
                  _assertNonReentrant();
                  // Skip overflow check as counter cannot be incremented that far.
                  unchecked {
                      // Increment current counter for the supplied offerer.
                      newCounter = ++_counters[msg.sender];
                  }
                  // 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;
          // prettier-ignore
          import {
              ConduitControllerInterface
          } from "../interfaces/ConduitControllerInterface.sol";
          // prettier-ignore
          import {
              ConsiderationEventsAndErrors
          } from "../interfaces/ConsiderationEventsAndErrors.sol";
          import "./ConsiderationConstants.sol";
          /**
           * @title ConsiderationBase
           * @author 0age
           * @notice ConsiderationBase contains immutable constants and constructor logic.
           */
          contract ConsiderationBase is 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 The derived domain separator.
               */
              function _deriveDomainSeparator() internal view returns (bytes32) {
                  // prettier-ignore
                  return keccak256(
                      abi.encode(
                          _EIP_712_DOMAIN_TYPEHASH,
                          _NAME_HASH,
                          _VERSION_HASH,
                          block.chainid,
                          address(this)
                      )
                  );
              }
              /**
               * @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.1"));
                  // Construct the OfferItem type string.
                  // prettier-ignore
                  bytes memory offerItemTypeString = abi.encodePacked(
                      "OfferItem(",
                          "uint8 itemType,",
                          "address token,",
                          "uint256 identifierOrCriteria,",
                          "uint256 startAmount,",
                          "uint256 endAmount",
                      ")"
                  );
                  // Construct the ConsiderationItem type string.
                  // prettier-ignore
                  bytes memory considerationItemTypeString = abi.encodePacked(
                      "ConsiderationItem(",
                          "uint8 itemType,",
                          "address token,",
                          "uint256 identifierOrCriteria,",
                          "uint256 startAmount,",
                          "uint256 endAmount,",
                          "address recipient",
                      ")"
                  );
                  // Construct the OrderComponents type string, not including the above.
                  // prettier-ignore
                  bytes memory orderComponentsPartialTypeString = abi.encodePacked(
                      "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.
                  // prettier-ignore
                  eip712DomainTypehash = keccak256(
                      abi.encodePacked(
                          "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);
                  // Derive OrderItem type hash via combination of relevant type strings.
                  orderTypehash = keccak256(
                      abi.encodePacked(
                          orderComponentsPartialTypeString,
                          considerationItemTypeString,
                          offerItemTypeString
                      )
                  );
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { SpentItem, ReceivedItem } 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 offerer   The offerer of the validated order.
               * @param zone      The zone of the validated order.
               */
              event OrderValidated(
                  bytes32 orderHash,
                  address indexed offerer,
                  address indexed zone
              );
              /**
               * @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.
               */
              error InvalidTime();
              /**
               * @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 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 ether is supplied as part of
               *      msg.value when fulfilling orders.
               */
              error InsufficientEtherSupplied();
              /**
               * @dev Revert with an error when an ether transfer reverts.
               */
              error EtherTransferGenericFailure(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.
               */
              error InvalidCanceller();
              /**
               * @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 ETH outside of matching orders.
               */
              error InvalidNativeOfferItem();
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ReentrancyErrors } from "../interfaces/ReentrancyErrors.sol";
          import "./ConsiderationConstants.sol";
          /**
           * @title ReentrancyGuard
           * @author 0age
           * @notice ReentrancyGuard contains a storage variable and related functionality
           *         for protecting against reentrancy.
           */
          contract ReentrancyGuard is ReentrancyErrors {
              // Prevent reentrant calls on protected functions.
              uint256 private _reentrancyGuard;
              /**
               * @dev Initialize the reentrancy guard during deployment.
               */
              constructor() {
                  // Initialize the reentrancy guard in a cleared state.
                  _reentrancyGuard = _NOT_ENTERED;
              }
              /**
               * @dev Internal function to ensure that the sentinel value for the
               *      reentrancy guard is not currently set and, if not, to set the
               *      sentinel value for the reentrancy guard.
               */
              function _setReentrancyGuard() internal {
                  // Ensure that the reentrancy guard is not already set.
                  _assertNonReentrant();
                  // Set the reentrancy guard.
                  _reentrancyGuard = _ENTERED;
              }
              /**
               * @dev Internal function to unset the reentrancy guard sentinel value.
               */
              function _clearReentrancyGuard() internal {
                  // Clear the reentrancy guard.
                  _reentrancyGuard = _NOT_ENTERED;
              }
              /**
               * @dev Internal view function to ensure that the sentinel value for the
                      reentrancy guard is not currently set.
               */
              function _assertNonReentrant() internal view {
                  // Ensure that the reentrancy guard is not currently set.
                  if (_reentrancyGuard != _NOT_ENTERED) {
                      revert NoReentrantCalls();
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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();
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          interface EIP1271Interface {
              function isValidSignature(bytes32 digest, bytes calldata signature)
                  external
                  view
                  returns (bytes4);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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.13;
          import "./ConsiderationConstants.sol";
          /**
           * @title LowLevelHelpers
           * @author 0age
           * @notice LowLevelHelpers contains logic for performing various low-level
           *         operations.
           */
          contract LowLevelHelpers {
              /**
               * @dev Internal view function to staticcall an arbitrary target with given
               *      calldata. Note that no data is written to memory and no contract
               *      size check is performed.
               *
               * @param target   The account to staticcall.
               * @param callData The calldata to supply when staticcalling the target.
               *
               * @return success The status of the staticcall to the target.
               */
              function _staticcall(address target, bytes memory callData)
                  internal
                  view
                  returns (bool success)
              {
                  assembly {
                      // Perform the staticcall.
                      success := staticcall(
                          gas(),
                          target,
                          add(callData, OneWord),
                          mload(callData),
                          0,
                          0
                      )
                  }
              }
              /**
               * @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 := div(
                              add(returndatasize(), AlmostOneWord),
                              OneWord
                          )
                          // Note: use the free memory pointer in place of msize() to work
                          // around a Yul warning that prevents accessing msize directly
                          // when the IR pipeline is activated.
                          let msizeWords := div(mload(FreeMemoryPointerSlot), OneWord)
                          // Next, compute the cost of the returndatacopy.
                          let cost := mul(CostPerWord, returnDataWords)
                          // Then, compute cost of new memory allocation.
                          if gt(returnDataWords, msizeWords) {
                              cost := add(
                                  cost,
                                  add(
                                      mul(sub(returnDataWords, msizeWords), CostPerWord),
                                      div(
                                          sub(
                                              mul(returnDataWords, returnDataWords),
                                              mul(msizeWords, msizeWords)
                                          ),
                                          MemoryExpansionCoefficient
                                      )
                                  )
                              )
                          }
                          // Finally, add a small constant and compare to gas remaining;
                          // bubble up the revert data if enough gas is still available.
                          if lt(add(cost, ExtraGasBuffer), gas()) {
                              // Copy returndata to memory; overwrite existing memory.
                              returndatacopy(0, 0, returndatasize())
                              // Revert, specifying memory region with copied returndata.
                              revert(0, returndatasize())
                          }
                      }
                  }
              }
              /**
               * @dev Internal pure function to determine if the first word of returndata
               *      matches an expected magic value.
               *
               * @param expected The expected magic value.
               *
               * @return A boolean indicating whether the expected value matches the one
               *         located in the first word of returndata.
               */
              function _doesNotMatchMagic(bytes4 expected) internal pure returns (bool) {
                  // Declare a variable for the value held by the return data buffer.
                  bytes4 result;
                  // Utilize assembly in order to read directly from returndata buffer.
                  assembly {
                      // Only put result on stack if return data is exactly one word.
                      if eq(returndatasize(), OneWord) {
                          // Copy the word directly from return data into scratch space.
                          returndatacopy(0, 0, OneWord)
                          // Take value from scratch space and place it on the stack.
                          result := mload(0)
                      }
                  }
                  // Return a boolean indicating whether expected and located value match.
                  return result != expected;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ItemType, Side } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              OfferItem,
              ConsiderationItem,
              ReceivedItem,
              OrderParameters,
              AdvancedOrder,
              Execution,
              FulfillmentComponent
          } from "./ConsiderationStructs.sol";
          import "./ConsiderationConstants.sol";
          // prettier-ignore
          import {
              FulfillmentApplicationErrors
          } from "../interfaces/FulfillmentApplicationErrors.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.
               *
               * @return execution The transfer performed as a result of the fulfillment.
               */
              function _applyFulfillment(
                  AdvancedOrder[] memory advancedOrders,
                  FulfillmentComponent[] calldata offerComponents,
                  FulfillmentComponent[] calldata considerationComponents
              ) internal pure returns (Execution memory execution) {
                  // Ensure 1+ of both offer and consideration components are supplied.
                  if (
                      offerComponents.length == 0 || considerationComponents.length == 0
                  ) {
                      revert OfferAndConsiderationRequiredOnFulfillment();
                  }
                  // Declare a new Execution struct.
                  Execution memory considerationExecution;
                  // Validate & aggregate consideration items to new Execution object.
                  _aggregateValidFulfillmentConsiderationItems(
                      advancedOrders,
                      considerationComponents,
                      considerationExecution
                  );
                  // Retrieve the consideration item from the execution struct.
                  ReceivedItem memory considerationItem = considerationExecution.item;
                  // Recipient does not need to be specified because it will always be set
                  // to that of the consideration.
                  // Validate & aggregate offer items to Execution object.
                  _aggregateValidFulfillmentOfferItems(
                      advancedOrders,
                      offerComponents,
                      execution
                  );
                  // Ensure offer and consideration share types, tokens and identifiers.
                  if (
                      execution.item.itemType != considerationItem.itemType ||
                      execution.item.token != considerationItem.token ||
                      execution.item.identifier != considerationItem.identifier
                  ) {
                      revert MismatchedFulfillmentOfferAndConsiderationComponents();
                  }
                  // If total consideration amount exceeds the offer amount...
                  if (considerationItem.amount > execution.item.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 -
                              execution.item.amount);
                      }
                      // Reduce total consideration amount to equal the offer amount.
                      considerationItem.amount = execution.item.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 = (execution.item.amount -
                              considerationItem.amount);
                      }
                      // Reduce total offer amount to equal the consideration amount.
                      execution.item.amount = considerationItem.amount;
                  }
                  // Reuse consideration recipient.
                  execution.item.recipient = considerationItem.recipient;
                  // Return the final execution that will be triggered for relevant items.
                  return execution; // Execution(considerationItem, 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) {
                          revert MissingFulfillmentComponentOnAggregation(side);
                      }
                      // If the fulfillment components are offer components...
                      if (side == Side.OFFER) {
                          // Set the supplied recipient on the execution item.
                          execution.item.recipient = payable(recipient);
                          // Return execution for aggregated items provided by offerer.
                          _aggregateValidFulfillmentOfferItems(
                              advancedOrders,
                              fulfillmentComponents,
                              execution
                          );
                      } else {
                          // Otherwise, fulfillment components are consideration
                          // components. Return execution for aggregated items provided by
                          // the fulfiller.
                          _aggregateValidFulfillmentConsiderationItems(
                              advancedOrders,
                              fulfillmentComponents,
                              execution
                          );
                          // Set the caller as the offerer on the execution.
                          execution.offerer = msg.sender;
                          // Set fulfiller conduit key as the conduit key on execution.
                          execution.conduitKey = fulfillerConduitKey;
                      }
                      // Set the offerer and recipient to null address if execution
                      // amount is zero. This will cause the execution item to be skipped.
                      if (execution.item.amount == 0) {
                          execution.offerer = address(0);
                          execution.item.recipient = payable(0);
                      }
                  }
              }
              /**
               * @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.
               */
              function _aggregateValidFulfillmentOfferItems(
                  AdvancedOrder[] memory advancedOrders,
                  FulfillmentComponent[] memory offerComponents,
                  Execution memory execution
              ) internal pure {
                  assembly {
                      // Declare function for reverts on invalid fulfillment data.
                      function throwInvalidFulfillmentComponentData() {
                          // Store the InvalidFulfillmentComponentData error signature.
                          mstore(0, InvalidFulfillmentComponentData_error_signature)
                          // Return, supplying InvalidFulfillmentComponentData signature.
                          revert(0, InvalidFulfillmentComponentData_error_len)
                      }
                      // Declare function for reverts due to arithmetic overflows.
                      function throwOverflow() {
                          // Store the Panic error signature.
                          mstore(0, Panic_error_signature)
                          // Store the arithmetic (0x11) panic code as initial argument.
                          mstore(Panic_error_offset, Panic_arithmetic)
                          // Return, supplying Panic signature and arithmetic code.
                          revert(0, Panic_error_length)
                      }
                      // Get position in offerComponents head.
                      let fulfillmentHeadPtr := add(offerComponents, 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(
                          // Calculate head position of advancedOrders[orderIndex].
                          add(add(advancedOrders, OneWord), mul(orderIndex, OneWord))
                      )
                      // Read the pointer to OrderParameters from the AdvancedOrder.
                      let paramsPtr := mload(orderPtr)
                      // Load the offer array pointer.
                      let offerArrPtr := mload(
                          add(paramsPtr, OrderParameters_offer_head_offset)
                      )
                      // Retrieve item index using an offset of the fulfillment pointer.
                      let itemIndex := mload(
                          add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                      )
                      // Only continue if the fulfillment is not invalid.
                      if iszero(lt(itemIndex, mload(offerArrPtr))) {
                          throwInvalidFulfillmentComponentData()
                      }
                      // Retrieve consideration item pointer using the item index.
                      let offerItemPtr := mload(
                          add(
                              // Get pointer to beginning of receivedItem.
                              add(offerArrPtr, OneWord),
                              // Calculate offset to pointer for desired order.
                              mul(itemIndex, OneWord)
                          )
                      )
                      // Declare a variable for the final aggregated item amount.
                      let amount := 0
                      // Create variable to track errors encountered with amount.
                      let errorBuffer := 0
                      // Only add offer amount to execution amount on a nonzero numerator.
                      if mload(add(orderPtr, AdvancedOrder_numerator_offset)) {
                          // Retrieve amount pointer using consideration item pointer.
                          let amountPtr := add(offerItemPtr, Common_amount_offset)
                          // Set the amount.
                          amount := mload(amountPtr)
                          // Zero out amount on item to indicate it is credited.
                          mstore(amountPtr, 0)
                          // Buffer indicating whether issues were found.
                          errorBuffer := iszero(amount)
                      }
                      // Retrieve the received item pointer.
                      let receivedItemPtr := mload(execution)
                      // Set the item type on the received item.
                      mstore(receivedItemPtr, mload(offerItemPtr))
                      // Set the token on the received item.
                      mstore(
                          add(receivedItemPtr, Common_token_offset),
                          mload(add(offerItemPtr, Common_token_offset))
                      )
                      // Set the identifier on the received item.
                      mstore(
                          add(receivedItemPtr, Common_identifier_offset),
                          mload(add(offerItemPtr, Common_identifier_offset))
                      )
                      // Set the offerer on returned execution using order pointer.
                      mstore(add(execution, Execution_offerer_offset), mload(paramsPtr))
                      // Set conduitKey on returned execution via offset of order pointer.
                      mstore(
                          add(execution, Execution_conduit_offset),
                          mload(add(paramsPtr, OrderParameters_conduit_offset))
                      )
                      // Calculate the hash of (itemType, token, identifier).
                      let dataHash := keccak256(
                          receivedItemPtr,
                          ReceivedItem_CommonParams_size
                      )
                      // Get position one word past last element in head of array.
                      let endPtr := add(
                          offerComponents,
                          mul(mload(offerComponents), OneWord)
                      )
                      // Iterate over remaining offer components.
                      // prettier-ignore
                      for {} lt(fulfillmentHeadPtr,  endPtr) {} {
                          // Increment the pointer to the fulfillment head by one word.
                          fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                          // Get the order index using the fulfillment pointer.
                          orderIndex := mload(mload(fulfillmentHeadPtr))
                          // Ensure the order index is in range.
                          if iszero(lt(orderIndex, mload(advancedOrders))) {
                            throwInvalidFulfillmentComponentData()
                          }
                          // Get pointer to AdvancedOrder element.
                          orderPtr := mload(
                              add(
                                  add(advancedOrders, OneWord),
                                  mul(orderIndex, OneWord)
                              )
                          )
                          // Only continue if numerator is not zero.
                          if iszero(mload(
                              add(orderPtr, AdvancedOrder_numerator_offset)
                          )) {
                            continue
                          }
                          // Read the pointer to OrderParameters from the AdvancedOrder.
                          paramsPtr := mload(orderPtr)
                          // Load offer array pointer.
                          offerArrPtr := mload(
                              add(
                                  paramsPtr,
                                  OrderParameters_offer_head_offset
                              )
                          )
                          // Get the item index using the fulfillment pointer.
                          itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord))
                          // Throw if itemIndex is out of the range of array.
                          if iszero(
                              lt(itemIndex, mload(offerArrPtr))
                          ) {
                              throwInvalidFulfillmentComponentData()
                          }
                          // Retrieve offer item pointer using index.
                          offerItemPtr := mload(
                              add(
                                  // Get pointer to beginning of receivedItem.
                                  add(offerArrPtr, OneWord),
                                  // Use offset to pointer for desired order.
                                  mul(itemIndex, OneWord)
                              )
                          )
                          // Retrieve amount pointer using offer item pointer.
                          let amountPtr := add(
                                offerItemPtr,
                                Common_amount_offset
                          )
                          // Add offer 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 credited.
                          mstore(amountPtr, 0)
                          // Ensure the indicated item matches original item.
                          if iszero(
                              and(
                                  and(
                                    // The offerer must match on both items.
                                    eq(
                                        mload(paramsPtr),
                                        mload(
                                            add(execution, Execution_offerer_offset)
                                        )
                                    ),
                                    // The conduit key must match on both items.
                                    eq(
                                        mload(
                                            add(
                                                paramsPtr,
                                                OrderParameters_conduit_offset
                                            )
                                        ),
                                        mload(
                                            add(
                                                execution,
                                                Execution_conduit_offset
                                            )
                                        )
                                    )
                                  ),
                                  // The itemType, token, and identifier must match.
                                  eq(
                                      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 the MissingItemAmount error signature.
                              mstore(0, MissingItemAmount_error_signature)
                              // Return, supplying MissingItemAmount signature.
                              revert(0, MissingItemAmount_error_len)
                          }
                          // If errorBuffer is not 1 or 0, the sum overflowed.
                          // Panic!
                          throwOverflow()
                      }
                  }
              }
              /**
               * @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.
               *
               * @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.
               */
              function _aggregateValidFulfillmentConsiderationItems(
                  AdvancedOrder[] memory advancedOrders,
                  FulfillmentComponent[] memory considerationComponents,
                  Execution memory execution
              ) internal pure {
                  // Utilize assembly in order to efficiently aggregate the items.
                  assembly {
                      // Declare function for reverts on invalid fulfillment data.
                      function throwInvalidFulfillmentComponentData() {
                          // Store the InvalidFulfillmentComponentData error signature.
                          mstore(0, InvalidFulfillmentComponentData_error_signature)
                          // Return, supplying InvalidFulfillmentComponentData signature.
                          revert(0, InvalidFulfillmentComponentData_error_len)
                      }
                      // Declare function for reverts due to arithmetic overflows.
                      function throwOverflow() {
                          // Store the Panic error signature.
                          mstore(0, Panic_error_signature)
                          // Store the arithmetic (0x11) panic code as initial argument.
                          mstore(Panic_error_offset, Panic_arithmetic)
                          // Return, supplying Panic signature and arithmetic code.
                          revert(0, Panic_error_length)
                      }
                      // Get position in considerationComponents head.
                      let fulfillmentHeadPtr := add(considerationComponents, 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(
                          // Calculate head position of advancedOrders[orderIndex].
                          add(add(advancedOrders, OneWord), mul(orderIndex, OneWord))
                      )
                      // Load consideration array pointer.
                      let considerationArrPtr := mload(
                          add(
                              // Read pointer to OrderParameters from the AdvancedOrder.
                              mload(orderPtr),
                              OrderParameters_consideration_head_offset
                          )
                      )
                      // Retrieve item index using an offset of the fulfillment pointer.
                      let itemIndex := mload(
                          add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                      )
                      // Ensure that the order index is not out of range.
                      if iszero(lt(itemIndex, mload(considerationArrPtr))) {
                          throwInvalidFulfillmentComponentData()
                      }
                      // Retrieve consideration item pointer using the item index.
                      let considerationItemPtr := mload(
                          add(
                              // Get pointer to beginning of receivedItem.
                              add(considerationArrPtr, OneWord),
                              // Calculate offset to pointer for desired order.
                              mul(itemIndex, OneWord)
                          )
                      )
                      // Declare a variable for the final aggregated item amount.
                      let amount := 0
                      // Create variable to track errors encountered with amount.
                      let errorBuffer := 0
                      // Only add consideration amount to execution amount if numerator is
                      // greater than zero.
                      if mload(add(orderPtr, AdvancedOrder_numerator_offset)) {
                          // Retrieve amount pointer using consideration item pointer.
                          let amountPtr := add(considerationItemPtr, Common_amount_offset)
                          // Set the amount.
                          amount := mload(amountPtr)
                          // Set error bit if amount is zero.
                          errorBuffer := iszero(amount)
                          // Zero out amount on item to indicate it is credited.
                          mstore(amountPtr, 0)
                      }
                      // Retrieve ReceivedItem pointer from Execution.
                      let receivedItem := mload(execution)
                      // 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.
                      mstore(
                          add(receivedItem, ReceivedItem_recipient_offset),
                          mload(
                              add(
                                  considerationItemPtr,
                                  ConsiderationItem_recipient_offset
                              )
                          )
                      )
                      // Calculate the hash of (itemType, token, identifier).
                      let dataHash := keccak256(
                          receivedItem,
                          ReceivedItem_CommonParams_size
                      )
                      // Get position one word past last element in head of array.
                      let endPtr := add(
                          considerationComponents,
                          mul(mload(considerationComponents), OneWord)
                      )
                      // Iterate over remaining offer components.
                      // prettier-ignore
                      for {} lt(fulfillmentHeadPtr,  endPtr) {} {
                          // Increment position in considerationComponents head.
                          fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                          // Get the order index using the fulfillment pointer.
                          orderIndex := mload(mload(fulfillmentHeadPtr))
                          // Ensure the order index is in range.
                          if iszero(lt(orderIndex, mload(advancedOrders))) {
                            throwInvalidFulfillmentComponentData()
                          }
                          // Get pointer to AdvancedOrder element.
                          orderPtr := mload(
                              add(
                                  add(advancedOrders, OneWord),
                                  mul(orderIndex, OneWord)
                              )
                          )
                          // Only continue if numerator is not zero.
                          if iszero(
                              mload(add(orderPtr, AdvancedOrder_numerator_offset))
                          ) {
                            continue
                          }
                          // Load consideration array pointer from OrderParameters.
                          considerationArrPtr := mload(
                              add(
                                  // Get pointer to OrderParameters from AdvancedOrder.
                                  mload(orderPtr),
                                  OrderParameters_consideration_head_offset
                              )
                          )
                          // Get the item index using the fulfillment pointer.
                          itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord))
                          // Check if itemIndex is within the range of array.
                          if iszero(lt(itemIndex, mload(considerationArrPtr))) {
                              throwInvalidFulfillmentComponentData()
                          }
                          // Retrieve consideration item pointer using index.
                          considerationItemPtr := mload(
                              add(
                                  // Get pointer to beginning of receivedItem.
                                  add(considerationArrPtr, OneWord),
                                  // Use offset to pointer for desired order.
                                  mul(itemIndex, OneWord)
                              )
                          )
                          // Retrieve amount pointer using consideration item pointer.
                          let amountPtr := add(
                                considerationItemPtr,
                                Common_amount_offset
                          )
                          // Add offer 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 credited.
                          mstore(amountPtr, 0)
                          // Ensure the indicated item matches original item.
                          if iszero(
                              and(
                                  // Item recipients must match.
                                  eq(
                                      mload(
                                          add(
                                              considerationItemPtr,
                                              ConsiderItem_recipient_offset
                                          )
                                      ),
                                      mload(
                                          add(
                                              receivedItem,
                                              ReceivedItem_recipient_offset
                                          )
                                      )
                                  ),
                                  // The itemType, token, identifier must match.
                                  eq(
                                    dataHash,
                                    keccak256(
                                      considerationItemPtr,
                                      ReceivedItem_CommonParams_size
                                    )
                                  )
                              )
                          ) {
                              // Throw if any of the requirements are not met.
                              throwInvalidFulfillmentComponentData()
                          }
                      }
                      // 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 the MissingItemAmount error signature.
                              mstore(0, MissingItemAmount_error_signature)
                              // Return, supplying MissingItemAmount signature.
                              revert(0, MissingItemAmount_error_len)
                          }
                          // If errorBuffer is not 1 or 0, the sum overflowed.
                          // Panic!
                          throwOverflow()
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          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.
               */
              error MismatchedFulfillmentOfferAndConsiderationComponents();
              /**
               * @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.13;
          import { ItemType, Side } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              OfferItem,
              ConsiderationItem,
              OrderParameters,
              AdvancedOrder,
              CriteriaResolver
          } from "./ConsiderationStructs.sol";
          import "./ConsiderationConstants.sol";
          // prettier-ignore
          import {
              CriteriaResolutionErrors
          } from "../interfaces/CriteriaResolutionErrors.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) {
                              revert OrderCriteriaResolverOutOfRange();
                          }
                          // Skip criteria resolution for order if not fulfilled.
                          if (advancedOrders[orderIndex].numerator == 0) {
                              continue;
                          }
                          // Retrieve the parameters for the order.
                          OrderParameters memory orderParameters = (
                              advancedOrders[orderIndex].parameters
                          );
                          // Read component index from memory and place it on the stack.
                          uint256 componentIndex = criteriaResolver.index;
                          // Declare values for item's type and criteria.
                          ItemType itemType;
                          uint256 identifierOrCriteria;
                          // If the criteria resolver refers to an offer item...
                          if (criteriaResolver.side == Side.OFFER) {
                              // Retrieve the offer.
                              OfferItem[] memory offer = orderParameters.offer;
                              // Ensure that the component index is in range.
                              if (componentIndex >= offer.length) {
                                  revert OfferCriteriaResolverOutOfRange();
                              }
                              // Retrieve relevant item using the component index.
                              OfferItem memory offerItem = offer[componentIndex];
                              // Read item type and criteria from memory & place on stack.
                              itemType = offerItem.itemType;
                              identifierOrCriteria = offerItem.identifierOrCriteria;
                              // Optimistically 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(3, eq(itemType, 4))
                              }
                              offerItem.itemType = newItemType;
                              // Optimistically update identifier w/ supplied identifier.
                              offerItem.identifierOrCriteria = criteriaResolver
                                  .identifier;
                          } else {
                              // Otherwise, the resolver refers to a consideration item.
                              ConsiderationItem[] memory consideration = (
                                  orderParameters.consideration
                              );
                              // Ensure that the component index is in range.
                              if (componentIndex >= consideration.length) {
                                  revert ConsiderationCriteriaResolverOutOfRange();
                              }
                              // Retrieve relevant item using order and component index.
                              ConsiderationItem memory considerationItem = (
                                  consideration[componentIndex]
                              );
                              // Read item type and criteria from memory & place on stack.
                              itemType = considerationItem.itemType;
                              identifierOrCriteria = (
                                  considerationItem.identifierOrCriteria
                              );
                              // Optimistically 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(3, eq(itemType, 4))
                              }
                              considerationItem.itemType = newItemType;
                              // Optimistically update identifier w/ supplied identifier.
                              considerationItem.identifierOrCriteria = (
                                  criteriaResolver.identifier
                              );
                          }
                          // Ensure the specified item type indicates criteria usage.
                          if (!_isItemWithCriteria(itemType)) {
                              revert CriteriaNotEnabledForItem();
                          }
                          // If criteria is not 0 (i.e. a collection-wide offer)...
                          if (identifierOrCriteria != uint256(0)) {
                              // Verify identifier inclusion in criteria root using proof.
                              _verifyProof(
                                  criteriaResolver.identifier,
                                  identifierOrCriteria,
                                  criteriaResolver.criteriaProof
                              );
                          }
                      }
                      // 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
                          );
                          // Read consideration length from memory and place on stack.
                          uint256 totalItems = orderParameters.consideration.length;
                          // Iterate over each consideration item on the order.
                          for (uint256 j = 0; j < totalItems; ++j) {
                              // Ensure item type no longer indicates criteria usage.
                              if (
                                  _isItemWithCriteria(
                                      orderParameters.consideration[j].itemType
                                  )
                              ) {
                                  revert UnresolvedConsiderationCriteria();
                              }
                          }
                          // Read offer length from memory and place on stack.
                          totalItems = orderParameters.offer.length;
                          // Iterate over each offer item on the order.
                          for (uint256 j = 0; j < totalItems; ++j) {
                              // Ensure item type no longer indicates criteria usage.
                              if (
                                  _isItemWithCriteria(orderParameters.offer[j].itemType)
                              ) {
                                  revert UnresolvedOfferCriteria();
                              }
                          }
                      }
                  }
              }
              /**
               * @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)
                      // Based on: https://github.com/Rari-Capital/solmate/blob/v7/src/utils/MerkleProof.sol
                      // 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(5, 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(5, 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) {
                      revert InvalidProof();
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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.
               */
              error OrderCriteriaResolverOutOfRange();
              /**
               * @dev Revert with an error if an offer item still has unresolved criteria
               *      after applying all criteria resolvers.
               */
              error UnresolvedOfferCriteria();
              /**
               * @dev Revert with an error if a consideration item still has unresolved
               *      criteria after applying all criteria resolvers.
               */
              error UnresolvedConsiderationCriteria();
              /**
               * @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.7;
          import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
          // prettier-ignore
          import {
              AdvancedOrder,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          contract TestZone is ZoneInterface {
              function isValidOrder(
                  bytes32 orderHash,
                  address caller,
                  address offerer,
                  bytes32 zoneHash
              ) external pure override returns (bytes4 validOrderMagicValue) {
                  orderHash;
                  caller;
                  offerer;
                  if (zoneHash == bytes32(uint256(1))) {
                      revert("Revert on zone hash 1");
                  } else if (zoneHash == bytes32(uint256(2))) {
                      assembly {
                          revert(0, 0)
                      }
                  }
                  validOrderMagicValue = zoneHash != bytes32(uint256(3))
                      ? ZoneInterface.isValidOrder.selector
                      : bytes4(0xffffffff);
              }
              function isValidOrderIncludingExtraData(
                  bytes32 orderHash,
                  address caller,
                  AdvancedOrder calldata order,
                  bytes32[] calldata priorOrderHashes,
                  CriteriaResolver[] calldata criteriaResolvers
              ) external pure override returns (bytes4 validOrderMagicValue) {
                  orderHash;
                  caller;
                  order;
                  priorOrderHashes;
                  criteriaResolvers;
                  if (order.extraData.length == 4) {
                      revert("Revert on extraData length 4");
                  } else if (order.extraData.length == 5) {
                      assembly {
                          revert(0, 0)
                      }
                  }
                  validOrderMagicValue = order.parameters.zoneHash != bytes32(uint256(3))
                      ? ZoneInterface.isValidOrder.selector
                      : bytes4(0xffffffff);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              AdvancedOrder,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          interface ZoneInterface {
              // Called by Consideration whenever extraData is not provided by the caller.
              function isValidOrder(
                  bytes32 orderHash,
                  address caller,
                  address offerer,
                  bytes32 zoneHash
              ) external view returns (bytes4 validOrderMagicValue);
              // Called by Consideration whenever any extraData is provided by the caller.
              function isValidOrderIncludingExtraData(
                  bytes32 orderHash,
                  address caller,
                  AdvancedOrder calldata order,
                  bytes32[] calldata priorOrderHashes,
                  CriteriaResolver[] calldata criteriaResolvers
              ) external view returns (bytes4 validOrderMagicValue);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
          import { OrderType } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import { AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol";
          import "./ConsiderationConstants.sol";
          // prettier-ignore
          import {
              ZoneInteractionErrors
          } from "../interfaces/ZoneInteractionErrors.sol";
          import { LowLevelHelpers } from "./LowLevelHelpers.sol";
          /**
           * @title ZoneInteraction
           * @author 0age
           * @notice ZoneInteraction contains logic related to interacting with zones.
           */
          contract ZoneInteraction is ZoneInteractionErrors, LowLevelHelpers {
              /**
               * @dev Internal view function to determine if an order has a restricted
               *      order type and, if so, to ensure that either the offerer or the zone
               *      are the fulfiller or that a staticcall to `isValidOrder` on the zone
               *      returns a magic value indicating that the order is currently valid.
               *
               * @param orderHash The hash of the order.
               * @param zoneHash  The hash to provide upon calling the zone.
               * @param orderType The type of the order.
               * @param offerer   The offerer in question.
               * @param zone      The zone in question.
               */
              function _assertRestrictedBasicOrderValidity(
                  bytes32 orderHash,
                  bytes32 zoneHash,
                  OrderType orderType,
                  address offerer,
                  address zone
              ) internal view {
                  // Order type 2-3 require zone or offerer be caller or zone to approve.
                  if (
                      uint256(orderType) > 1 &&
                      msg.sender != zone &&
                      msg.sender != offerer
                  ) {
                      // Perform minimal staticcall to the zone.
                      _callIsValidOrder(zone, orderHash, offerer, zoneHash);
                  }
              }
              function _callIsValidOrder(
                  address zone,
                  bytes32 orderHash,
                  address offerer,
                  bytes32 zoneHash
              ) internal view {
                  // Perform minimal staticcall to the zone.
                  bool success = _staticcall(
                      zone,
                      abi.encodeWithSelector(
                          ZoneInterface.isValidOrder.selector,
                          orderHash,
                          msg.sender,
                          offerer,
                          zoneHash
                      )
                  );
                  // Ensure call was successful and returned the correct magic value.
                  _assertIsValidOrderStaticcallSuccess(success, orderHash);
              }
              /**
               * @dev Internal view function to determine whether an order is a restricted
               *      order and, if so, to ensure that it was either submitted by the
               *      offerer or the zone for the order, or that the zone returns the
               *      expected magic value upon performing a staticcall to `isValidOrder`
               *      or `isValidOrderIncludingExtraData` depending on whether the order
               *      fulfillment specifies extra data or criteria resolvers.
               *
               * @param advancedOrder     The advanced order in question.
               * @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 priorOrderHashes  The order hashes of each order supplied prior to
               *                          the current order as part of a "match" variety
               *                          of order fulfillment (e.g. this array will be
               *                          empty for single or "fulfill available").
               * @param orderHash         The hash of the order.
               * @param zoneHash          The hash to provide upon calling the zone.
               * @param orderType         The type of the order.
               * @param offerer           The offerer in question.
               * @param zone              The zone in question.
               */
              function _assertRestrictedAdvancedOrderValidity(
                  AdvancedOrder memory advancedOrder,
                  CriteriaResolver[] memory criteriaResolvers,
                  bytes32[] memory priorOrderHashes,
                  bytes32 orderHash,
                  bytes32 zoneHash,
                  OrderType orderType,
                  address offerer,
                  address zone
              ) internal view {
                  // Order type 2-3 require zone or offerer be caller or zone to approve.
                  if (
                      uint256(orderType) > 1 &&
                      msg.sender != zone &&
                      msg.sender != offerer
                  ) {
                      // If no extraData or criteria resolvers are supplied...
                      if (
                          advancedOrder.extraData.length == 0 &&
                          criteriaResolvers.length == 0
                      ) {
                          // Perform minimal staticcall to the zone.
                          _callIsValidOrder(zone, orderHash, offerer, zoneHash);
                      } else {
                          // Otherwise, extra data or criteria resolvers were supplied; in
                          // that event, perform a more verbose staticcall to the zone.
                          bool success = _staticcall(
                              zone,
                              abi.encodeWithSelector(
                                  ZoneInterface.isValidOrderIncludingExtraData.selector,
                                  orderHash,
                                  msg.sender,
                                  advancedOrder,
                                  priorOrderHashes,
                                  criteriaResolvers
                              )
                          );
                          // Ensure call was successful and returned correct magic value.
                          _assertIsValidOrderStaticcallSuccess(success, orderHash);
                      }
                  }
              }
              /**
               * @dev Internal view function to ensure that a staticcall to `isValidOrder`
               *      or `isValidOrderIncludingExtraData` as part of validating a
               *      restricted order that was not submitted by the named offerer or zone
               *      was successful and returned the required magic value.
               *
               * @param success   A boolean indicating the status of the staticcall.
               * @param orderHash The order hash of the order in question.
               */
              function _assertIsValidOrderStaticcallSuccess(
                  bool success,
                  bytes32 orderHash
              ) internal view {
                  // If the call failed...
                  if (!success) {
                      // Revert and pass reason along if one was returned.
                      _revertWithReasonIfOneIsReturned();
                      // Otherwise, revert with a generic error message.
                      revert InvalidRestrictedOrder(orderHash);
                  }
                  // Ensure result was extracted and matches isValidOrder magic value.
                  if (_doesNotMatchMagic(ZoneInterface.isValidOrder.selector)) {
                      revert InvalidRestrictedOrder(orderHash);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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 staticcall to `isValidOrder`.
               *
               * @param orderHash The order hash for the invalid restricted order.
               */
              error InvalidRestrictedOrder(bytes32 orderHash);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
          // prettier-ignore
          import {
              OrderType,
              ItemType,
              BasicOrderRouteType
          } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              AdditionalRecipient,
              BasicOrderParameters,
              OfferItem,
              ConsiderationItem,
              SpentItem,
              ReceivedItem
          } from "./ConsiderationStructs.sol";
          import { OrderValidator } from "./OrderValidator.sol";
          import "./ConsiderationConstants.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.
               *
               * @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` in order to receive those
               *                   items.
               *
               * @return A boolean indicating whether the order has been fulfilled.
               */
              function _validateAndFulfillBasicOrder(
                  BasicOrderParameters calldata parameters
              ) 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;
                  // 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 Eth (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) {
                          revert InvalidMsgValue(msg.value);
                      }
                  }
                  // Declare more arguments that will be derived from route and calldata.
                  address additionalRecipientsToken;
                  ItemType offeredItemType;
                  bool offerTypeIsAdditionalRecipientsType;
                  // 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 Eth (0).
                          receivedItemType := add(
                              mul(sub(route, 2), gt(route, 2)),
                              eq(route, 2)
                          )
                          // If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3,
                          // offeredItemType = route. Route is 0 or 1, it is route + 2.
                          offeredItemType := sub(
                              add(route, mul(iszero(additionalRecipientsItemType), 2)),
                              mul(
                                  offerTypeIsAdditionalRecipientsType,
                                  add(receivedItemType, 1)
                              )
                          )
                      }
                      // Derive & validate order using parameters and update order status.
                      _prepareBasicFulfillmentFromCalldata(
                          parameters,
                          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,
                              mul(offerTypeIsAdditionalRecipientsType, OneWord)
                          )
                      )
                  }
                  // Transfer tokens based on the route.
                  if (additionalRecipientsItemType == ItemType.NATIVE) {
                      // Ensure neither the token nor the identifier parameters are set.
                      if (
                          (uint160(parameters.considerationToken) |
                              parameters.considerationIdentifier) != 0
                      ) {
                          revert UnusedItemParameters();
                      }
                      // Transfer the ERC721 or ERC1155 item, bypassing the accumulator.
                      _transferIndividual721Or1155Item(
                          offeredItemType,
                          parameters.offerToken,
                          parameters.offerer,
                          msg.sender,
                          parameters.offerIdentifier,
                          parameters.offerAmount,
                          conduitKey
                      );
                      // Transfer native to recipients, return excess to caller & wrap up.
                      _transferEthAndFinalize(
                          parameters.considerationAmount,
                          parameters.offerer,
                          parameters.additionalRecipients
                      );
                  } 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(
                              parameters.offerToken,
                              parameters.offerer,
                              msg.sender,
                              parameters.offerIdentifier,
                              parameters.offerAmount,
                              conduitKey,
                              accumulator
                          );
                      } else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) {
                          // Transfer ERC1155 to caller with offerer's conduit preference.
                          _transferERC1155(
                              parameters.offerToken,
                              parameters.offerer,
                              msg.sender,
                              parameters.offerIdentifier,
                              parameters.offerAmount,
                              conduitKey,
                              accumulator
                          );
                      } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) {
                          // Transfer ERC721 to offerer using caller's conduit preference.
                          _transferERC721(
                              parameters.considerationToken,
                              msg.sender,
                              parameters.offerer,
                              parameters.considerationIdentifier,
                              parameters.considerationAmount,
                              conduitKey,
                              accumulator
                          );
                      } else {
                          // route == BasicOrderRouteType.ERC1155_TO_ERC20
                          // Transfer ERC1155 to offerer with caller's conduit preference.
                          _transferERC1155(
                              parameters.considerationToken,
                              msg.sender,
                              parameters.offerer,
                              parameters.considerationIdentifier,
                              parameters.considerationAmount,
                              conduitKey,
                              accumulator
                          );
                      }
                      // Transfer ERC20 tokens to all recipients and wrap up.
                      _transferERC20AndFinalize(
                          parameters.offerer,
                          parameters,
                          offerTypeIsAdditionalRecipientsType,
                          accumulator
                      );
                      // Trigger any remaining accumulated transfers via call to conduit.
                      _triggerIfArmed(accumulator);
                  }
                  // 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. It does not clear the expanded
               *      memory regions used, nor does it update the free memory pointer, so
               *      other direct memory access must not assume that unused memory is
               *      empty.
               *
               * @param parameters                   The parameters of the basic order.
               * @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.
               */
              function _prepareBasicFulfillmentFromCalldata(
                  BasicOrderParameters calldata parameters,
                  OrderType orderType,
                  ItemType receivedItemType,
                  ItemType additionalRecipientsItemType,
                  address additionalRecipientsToken,
                  ItemType offeredItemType
              ) internal {
                  // Ensure this function cannot be triggered during a reentrant call.
                  _setReentrancyGuard();
                  // Ensure current timestamp falls between order start time and end time.
                  _verifyTime(parameters.startTime, parameters.endTime, true);
                  // Verify that calldata offsets for all dynamic types were produced by
                  // default encoding. This ensures that the constants we use 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();
                  // Ensure supplied consideration array length is not less than original.
                  _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
                      parameters.additionalRecipients.length,
                      parameters.totalOriginalAdditionalRecipients
                  );
                  // Declare stack element for the order hash.
                  bytes32 orderHash;
                  {
                      /**
                       * 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 length of the additional recipients array.
                          let totalAdditionalRecipients := calldataload(
                              BasicOrder_additionalRecipients_length_cdPtr
                          )
                          // Calculate pointer to length of OrderFulfilled consideration
                          // array.
                          let eventConsiderationArrPtr := add(
                              OrderFulfilled_consideration_length_baseOffset,
                              mul(totalAdditionalRecipients, OneWord)
                          )
                          // Set the length of the consideration array to the number of
                          // additional recipients, plus one for the primary consideration
                          // item.
                          mstore(
                              eventConsiderationArrPtr,
                              add(
                                  calldataload(
                                      BasicOrder_additionalRecipients_length_cdPtr
                                  ),
                                  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 considerations signed by
                           * the offerer aside from the primary consideration 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)
                          // Read length of the additionalRecipients array from calldata
                          // and iterate.
                          totalAdditionalRecipients := calldataload(
                              BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                          )
                          let i := 0
                          // prettier-ignore
                          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(AdditionalRecipients_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,
                                  AdditionalRecipients_size
                              )
                              // 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,
                                  mul(add(totalAdditionalRecipients, 1), OneWord)
                              )
                          )
                          /*
                           * 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_additionalRecipients_length_cdPtr
                          )
                          // prettier-ignore
                          for {} lt(i, totalAdditionalRecipients) {
                              i := add(i, 1)
                          } {
                              // Retrieve calldata pointer for additional recipient.
                              let additionalRecipientCdPtr := add(
                                  BasicOrder_additionalRecipients_data_cdPtr,
                                  mul(AdditionalRecipients_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
                              )
                          }
                      }
                  }
                  {
                      /**
                       * 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))
                          /*
                           * 3. Write SpentItem to offer array in OrderFulfilled event.
                           */
                          let eventConsiderationArrPtr := add(
                              OrderFulfilled_offer_length_baseOffset,
                              mul(
                                  calldataload(
                                      BasicOrder_additionalRecipients_length_cdPtr
                                  ),
                                  OneWord
                              )
                          )
                          // Set a length of 1 for the offer array.
                          mstore(eventConsiderationArrPtr, 1)
                          // Write itemType to the SpentItem struct.
                          mstore(add(eventConsiderationArrPtr, OneWord), offeredItemType)
                          // Copy calldata region with (offerToken, offerIdentifier,
                          // offerAmount) from OrderParameters to (token, identifier,
                          // amount) in SpentItem struct.
                          calldatacopy(
                              add(eventConsiderationArrPtr, AdditionalRecipients_size),
                              BasicOrder_offerToken_cdPtr,
                              ThreeWords
                          )
                      }
                  }
                  {
                      /**
                       * 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,
                          mul(
                              calldataload(BasicOrder_additionalRecipients_length_cdPtr),
                              OneWord
                          )
                      )
                      // 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
                      )
                      // 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_additionalRecipients_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)
                  }
                  // Determine whether order is restricted and, if so, that it is valid.
                  _assertRestrictedBasicOrderValidity(
                      orderHash,
                      parameters.zoneHash,
                      orderType,
                      parameters.offerer,
                      parameters.zone
                  );
                  // Verify and update the status of the derived order.
                  _validateBasicOrderAndUpdateStatus(
                      orderHash,
                      parameters.offerer,
                      parameters.signature
                  );
              }
              /**
               * @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.
               *
               * @param amount               The amount to transfer.
               * @param to                   The recipient of the native token transfer.
               * @param additionalRecipients The additional recipients of the order.
               */
              function _transferEthAndFinalize(
                  uint256 amount,
                  address payable to,
                  AdditionalRecipient[] calldata additionalRecipients
              ) internal {
                  // Put ether value supplied by the caller on the stack.
                  uint256 etherRemaining = msg.value;
                  // Retrieve total number of additional recipients and place on stack.
                  uint256 totalAdditionalRecipients = additionalRecipients.length;
                  // Skip overflow check as for loop is indexed starting at zero.
                  unchecked {
                      // Iterate over each additional recipient.
                      for (uint256 i = 0; i < totalAdditionalRecipients; ++i) {
                          // Retrieve the additional recipient.
                          AdditionalRecipient calldata additionalRecipient = (
                              additionalRecipients[i]
                          );
                          // Read ether amount to transfer to recipient & place on stack.
                          uint256 additionalRecipientAmount = additionalRecipient.amount;
                          // Ensure that sufficient Ether is available.
                          if (additionalRecipientAmount > etherRemaining) {
                              revert InsufficientEtherSupplied();
                          }
                          // Transfer Ether to the additional recipient.
                          _transferEth(
                              additionalRecipient.recipient,
                              additionalRecipientAmount
                          );
                          // Reduce ether value available. Skip underflow check as
                          // subtracted value is confirmed above as less than remaining.
                          etherRemaining -= additionalRecipientAmount;
                      }
                  }
                  // Ensure that sufficient Ether is still available.
                  if (amount > etherRemaining) {
                      revert InsufficientEtherSupplied();
                  }
                  // Transfer Ether to the offerer.
                  _transferEth(to, amount);
                  // If any Ether remains after transfers, return it to the caller.
                  if (etherRemaining > amount) {
                      // Skip underflow check as etherRemaining > amount.
                      unchecked {
                          // Transfer remaining Ether to the caller.
                          _transferEth(payable(msg.sender), etherRemaining - amount);
                      }
                  }
              }
              /**
               * @dev Internal function to transfer ERC20 tokens to a given recipient as
               *      part of basic order fulfillment.
               *
               * @param offerer     The offerer of the fulfiller order.
               * @param parameters  The basic order parameters.
               * @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(
                  address offerer,
                  BasicOrderParameters calldata parameters,
                  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 and msg.sender as to value.
                          from = offerer;
                          to = msg.sender;
                          // Use offer token and related values if token is from offerer.
                          token = parameters.offerToken;
                          identifier = parameters.offerIdentifier;
                          amount = parameters.offerAmount;
                      } else {
                          // Use msg.sender as from value and offerer as to value.
                          from = msg.sender;
                          to = offerer;
                          // Otherwise, use consideration token and related values.
                          token = parameters.considerationToken;
                          identifier = parameters.considerationIdentifier;
                          amount = parameters.considerationAmount;
                      }
                      // Ensure that no identifier is supplied.
                      if (identifier != 0) {
                          revert UnusedItemParameters();
                      }
                  }
                  // 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,
                              mul(fromOfferer, OneWord)
                          )
                      )
                  }
                  // Retrieve total number of additional recipients and place on stack.
                  uint256 totalAdditionalRecipients = (
                      parameters.additionalRecipients.length
                  );
                  // Iterate over each additional recipient.
                  for (uint256 i = 0; i < totalAdditionalRecipients; ) {
                      // Retrieve the additional recipient.
                      AdditionalRecipient calldata additionalRecipient = (
                          parameters.additionalRecipients[i]
                      );
                      uint256 additionalRecipientAmount = additionalRecipient.amount;
                      // Decrement the amount to transfer to fulfiller if indicated.
                      if (fromOfferer) {
                          amount -= additionalRecipientAmount;
                      }
                      // Transfer ERC20 tokens to additional recipient given approval.
                      _transferERC20(
                          token,
                          from,
                          additionalRecipient.recipient,
                          additionalRecipientAmount,
                          conduitKey,
                          accumulator
                      );
                      // Skip overflow check as for loop is indexed starting at zero.
                      unchecked {
                          ++i;
                      }
                  }
                  // 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.13;
          import { OrderType } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              OrderParameters,
              Order,
              AdvancedOrder,
              OrderComponents,
              OrderStatus,
              CriteriaResolver
          } from "./ConsiderationStructs.sol";
          import "./ConsiderationConstants.sol";
          import { Executor } from "./Executor.sol";
          import { ZoneInteraction } from "./ZoneInteraction.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;
              /**
               * @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 and update the status of a basic order.
               *
               * @param orderHash The hash of the order.
               * @param offerer   The offerer of the order.
               * @param signature A signature from the offerer indicating that the order
               *                  has been approved.
               */
              function _validateBasicOrderAndUpdateStatus(
                  bytes32 orderHash,
                  address offerer,
                  bytes memory signature
              ) internal {
                  // Retrieve the order status for the given order hash.
                  OrderStatus storage orderStatus = _orderStatus[orderHash];
                  // Ensure order is fillable and is not cancelled.
                  _verifyOrderStatus(
                      orderHash,
                      orderStatus,
                      true, // Only allow unused orders when fulfilling basic orders.
                      true // Signifies to revert if the order is invalid.
                  );
                  // If the order is not already validated, verify the supplied signature.
                  if (!orderStatus.isValidated) {
                      _verifySignature(offerer, orderHash, signature);
                  }
                  // Update order status as fully filled, packing struct values.
                  orderStatus.isValidated = true;
                  orderStatus.isCancelled = false;
                  orderStatus.numerator = 1;
                  orderStatus.denominator = 1;
              }
              /**
               * @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 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 revertOnInvalid   A boolean indicating whether to revert if the
               *                          order is invalid due to the time or status.
               * @param priorOrderHashes  The order hashes of each order supplied prior to
               *                          the current order as part of a "match" variety
               *                          of order fulfillment (e.g. this array will be
               *                          empty for single or "fulfill available").
               *
               * @return orderHash      The order hash.
               * @return newNumerator   A value indicating the portion of the order that
               *                        will be filled.
               * @return newDenominator A value indicating the total size of the order.
               */
              function _validateOrderAndUpdateStatus(
                  AdvancedOrder memory advancedOrder,
                  CriteriaResolver[] memory criteriaResolvers,
                  bool revertOnInvalid,
                  bytes32[] memory priorOrderHashes
              )
                  internal
                  returns (
                      bytes32 orderHash,
                      uint256 newNumerator,
                      uint256 newDenominator
                  )
              {
                  // 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.
                  uint256 numerator = uint256(advancedOrder.numerator);
                  uint256 denominator = uint256(advancedOrder.denominator);
                  // Ensure that the supplied numerator and denominator are valid.
                  if (numerator > denominator || numerator == 0) {
                      revert BadFraction();
                  }
                  // If attempting partial fill (n < d) check order type & ensure support.
                  if (
                      numerator < denominator &&
                      _doesNotSupportPartialFills(orderParameters.orderType)
                  ) {
                      // Revert if partial fill was attempted on an unsupported order.
                      revert PartialFillsNotEnabledForOrder();
                  }
                  // Retrieve current counter & use it w/ parameters to derive order hash.
                  orderHash = _assertConsiderationLengthAndGetOrderHash(orderParameters);
                  // Ensure restricted orders have a valid submitter or pass a zone check.
                  _assertRestrictedAdvancedOrderValidity(
                      advancedOrder,
                      criteriaResolvers,
                      priorOrderHashes,
                      orderHash,
                      orderParameters.zoneHash,
                      orderParameters.orderType,
                      orderParameters.offerer,
                      orderParameters.zone
                  );
                  // Retrieve the order status using the derived order hash.
                  OrderStatus storage orderStatus = _orderStatus[orderHash];
                  // Ensure order is fillable and is not cancelled.
                  if (
                      !_verifyOrderStatus(
                          orderHash,
                          orderStatus,
                          false, // Allow partially used orders to be filled.
                          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
                      );
                  }
                  // Read filled amount as numerator and denominator and put on the stack.
                  uint256 filledNumerator = orderStatus.numerator;
                  uint256 filledDenominator = orderStatus.denominator;
                  // If order (orderStatus) currently has a non-zero denominator it is
                  // partially filled.
                  if (filledDenominator != 0) {
                      // If denominator of 1 supplied, fill all remaining amount on order.
                      if (denominator == 1) {
                          // Scale numerator & denominator to match current denominator.
                          numerator = filledDenominator;
                          denominator = filledDenominator;
                      }
                      // Otherwise, if supplied denominator differs from current one...
                      else if (filledDenominator != denominator) {
                          // scale current numerator by the supplied denominator, then...
                          filledNumerator *= denominator;
                          // the supplied numerator & denominator by current denominator.
                          numerator *= filledDenominator;
                          denominator *= filledDenominator;
                      }
                      // Once adjusted, if current+supplied numerator exceeds denominator:
                      if (filledNumerator + numerator > denominator) {
                          // Skip underflow check: denominator >= orderStatus.numerator
                          unchecked {
                              // Reduce current numerator so it + supplied = denominator.
                              numerator = denominator - filledNumerator;
                          }
                      }
                      // Increment the filled numerator by the new numerator.
                      filledNumerator += numerator;
                      // Use assembly to ensure fractional amounts are below max uint120.
                      assembly {
                          // 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 {
                                  for {
                                  } _b {
                                  } {
                                      let _c := _b
                                      _b := mod(_a, _c)
                                      _a := _c
                                  }
                                  out := _a
                              }
                              let scaleDown := gcd(
                                  numerator,
                                  gcd(filledNumerator, denominator)
                              )
                              // Ensure that the divisor is at least one.
                              let safeScaleDown := add(scaleDown, iszero(scaleDown))
                              // Scale all fractional values down by gcd.
                              numerator := div(numerator, safeScaleDown)
                              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_signature)
                                  // Set arithmetic (0x11) panic code as initial argument.
                                  mstore(Panic_error_offset, Panic_arithmetic)
                                  // Return, supplying Panic signature & arithmetic code.
                                  revert(0, Panic_error_length)
                              }
                          }
                      }
                      // Skip overflow check: checked above unless numerator is reduced.
                      unchecked {
                          // Update order status and fill amount, packing struct values.
                          orderStatus.isValidated = true;
                          orderStatus.isCancelled = false;
                          orderStatus.numerator = uint120(filledNumerator);
                          orderStatus.denominator = uint120(denominator);
                      }
                  } else {
                      // Update order status and fill amount, packing struct values.
                      orderStatus.isValidated = true;
                      orderStatus.isCancelled = false;
                      orderStatus.numerator = uint120(numerator);
                      orderStatus.denominator = uint120(denominator);
                  }
                  // Return order hash, a modified numerator, and a modified denominator.
                  return (orderHash, numerator, denominator);
              }
              /**
               * @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`.
               *
               * @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;
                  address offerer;
                  address zone;
                  // 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];
                          offerer = order.offerer;
                          zone = order.zone;
                          // Ensure caller is either offerer or zone of the order.
                          if (msg.sender != offerer && msg.sender != zone) {
                              revert InvalidCanceller();
                          }
                          // Derive order hash using the order parameters and the counter.
                          bytes32 orderHash = _deriveOrderHash(
                              OrderParameters(
                                  offerer,
                                  zone,
                                  order.offer,
                                  order.consideration,
                                  order.orderType,
                                  order.startTime,
                                  order.endTime,
                                  order.zoneHash,
                                  order.salt,
                                  order.conduitKey,
                                  order.consideration.length
                              ),
                              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;
                      }
                  }
                  // 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[] calldata 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; ) {
                          // Retrieve the order.
                          Order calldata order = orders[i];
                          // Retrieve the order parameters.
                          OrderParameters calldata orderParameters = order.parameters;
                          // 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.
                              true // Signifies to revert if the order is invalid.
                          );
                          // If the order has not already been validated...
                          if (!orderStatus.isValidated) {
                              // 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,
                                  offerer,
                                  orderParameters.zone
                              );
                          }
                          // Increment counter inside body of the loop for gas efficiency.
                          ++i;
                      }
                  }
                  // 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.
               *
               * @return isFullOrder A boolean indicating whether the order type only
               *                     supports full fills.
               */
              function _doesNotSupportPartialFills(OrderType orderType)
                  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.
                  assembly {
                      // Equivalent to `uint256(orderType) & 1 == 0`.
                      isFullOrder := iszero(and(orderType, 1))
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          import { ItemType } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              OfferItem,
              ConsiderationItem,
              SpentItem,
              ReceivedItem,
              OrderParameters,
              Order,
              AdvancedOrder,
              CriteriaResolver
          } from "./ConsiderationStructs.sol";
          import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol";
          import { CriteriaResolution } from "./CriteriaResolution.sol";
          import { AmountDeriver } from "./AmountDeriver.sol";
          import "./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) {
                  // Ensure this function cannot be triggered during a reentrant call.
                  _setReentrancyGuard();
                  // Declare empty bytes32 array (unused, will remain empty).
                  bytes32[] memory priorOrderHashes;
                  // Validate order, update status, and determine fraction to fill.
                  (
                      bytes32 orderHash,
                      uint256 fillNumerator,
                      uint256 fillDenominator
                  ) = _validateOrderAndUpdateStatus(
                          advancedOrder,
                          criteriaResolvers,
                          true,
                          priorOrderHashes
                      );
                  // 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);
                  // Retrieve the order parameters after applying criteria resolvers.
                  OrderParameters memory orderParameters = advancedOrders[0].parameters;
                  // Perform each item transfer with the appropriate fractional amount.
                  _applyFractionsAndTransferEach(
                      orderParameters,
                      fillNumerator,
                      fillDenominator,
                      fulfillerConduitKey,
                      recipient
                  );
                  // 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 transfer each item contained in a given single
               *      order fulfillment after applying a respective fraction to the amount
               *      being transferred.
               *
               * @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 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 _applyFractionsAndTransferEach(
                  OrderParameters memory orderParameters,
                  uint256 numerator,
                  uint256 denominator,
                  bytes32 fulfillerConduitKey,
                  address recipient
              ) internal {
                  // Read start time & end time from order parameters and place on stack.
                  uint256 startTime = orderParameters.startTime;
                  uint256 endTime = orderParameters.endTime;
                  // 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 in order to recast the type of a function, we need to
                  // create a local variable to reference the internal function definition
                  // (using the same type) and a local variable with the desired type,
                  // and then cast the original function pointer 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 {
                      // Declare a virtual function pointer taking an OfferItem argument.
                      function(OfferItem memory, address, bytes32, bytes memory)
                          internal _transferOfferItem;
                      {
                          // Assign _transfer function to a new function pointer (it takes
                          // a ReceivedItem as its initial argument)
                          function(ReceivedItem memory, address, bytes32, bytes memory)
                              internal _transferReceivedItem = _transfer;
                          // Utilize assembly to override the virtual function pointer.
                          assembly {
                              // Cast initial ReceivedItem type to an OfferItem type.
                              _transferOfferItem := _transferReceivedItem
                          }
                      }
                      // 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];
                          // Offer items for the native token can not be received
                          // outside of a match order function.
                          if (offerItem.itemType == ItemType.NATIVE) {
                              revert InvalidNativeOfferItem();
                          }
                          // 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,
                                  false
                              );
                              // 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
                                  )
                              }
                          }
                          // Transfer the item from the offerer to the recipient.
                          _transferOfferItem(
                              offerItem,
                              orderParameters.offerer,
                              orderParameters.conduitKey,
                              accumulator
                          );
                      }
                  }
                  // Put ether value supplied by the caller on the stack.
                  uint256 etherRemaining = msg.value;
                  /**
                   * 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 {
                      // Declare virtual function pointer with ConsiderationItem argument.
                      function(ConsiderationItem memory, address, bytes32, bytes memory)
                          internal _transferConsiderationItem;
                      {
                          // Reassign _transfer function to a new function pointer (it
                          // takes a ReceivedItem as its initial argument).
                          function(ReceivedItem memory, address, bytes32, bytes memory)
                              internal _transferReceivedItem = _transfer;
                          // Utilize assembly to override the virtual function pointer.
                          assembly {
                              // Cast ReceivedItem type to ConsiderationItem type.
                              _transferConsiderationItem := _transferReceivedItem
                          }
                      }
                      // 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,
                              true
                          );
                          // 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
                                      )
                                  )
                              )
                          }
                          // Reduce available value if offer spent ETH or a native token.
                          if (considerationItem.itemType == ItemType.NATIVE) {
                              // Ensure that sufficient native tokens are still available.
                              if (amount > etherRemaining) {
                                  revert InsufficientEtherSupplied();
                              }
                              // Skip underflow check as a comparison has just been made.
                              etherRemaining -= amount;
                          }
                          // Transfer item from caller to recipient specified by the item.
                          _transferConsiderationItem(
                              considerationItem,
                              msg.sender,
                              fulfillerConduitKey,
                              accumulator
                          );
                      }
                  }
                  // Trigger any remaining accumulated transfers via call to the conduit.
                  _triggerIfArmed(accumulator);
                  // If any ether remains after fulfillments...
                  if (etherRemaining != 0) {
                      // return it to the caller.
                      _transferEth(payable(msg.sender), etherRemaining);
                  }
              }
              /**
               * @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 fulfiller     The fulfiller 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 fulfiller,
                  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,
                      fulfiller,
                      spentItems,
                      receivedItems
                  );
              }
              /**
               * @dev Internal pure function to convert an order to an advanced order with
               *      numerator and denominator of 1 and empty extraData.
               *
               * @param order The order to convert.
               *
               * @return advancedOrder The new advanced order.
               */
              function _convertOrderToAdvanced(Order calldata order)
                  internal
                  pure
                  returns (AdvancedOrder memory advancedOrder)
              {
                  // Convert to partial order (1/1 or full fill) and return new value.
                  advancedOrder = AdvancedOrder(
                      order.parameters,
                      1,
                      1,
                      order.signature,
                      ""
                  );
              }
              /**
               * @dev Internal pure function to convert an array of orders to an array of
               *      advanced orders with numerator and denominator of 1.
               *
               * @param orders The orders to convert.
               *
               * @return advancedOrders The new array of partial orders.
               */
              function _convertOrdersToAdvanced(Order[] calldata orders)
                  internal
                  pure
                  returns (AdvancedOrder[] memory advancedOrders)
              {
                  // Read the number of orders from calldata and place on the stack.
                  uint256 totalOrders = orders.length;
                  // Allocate new empty array for each partial order in memory.
                  advancedOrders = new AdvancedOrder[](totalOrders);
                  // Skip overflow check as the index for the loop starts at zero.
                  unchecked {
                      // Iterate over the given orders.
                      for (uint256 i = 0; i < totalOrders; ++i) {
                          // Convert to partial order (1/1 or full fill) and update array.
                          advancedOrders[i] = _convertOrderToAdvanced(orders[i]);
                      }
                  }
                  // Return the array of advanced orders.
                  return advancedOrders;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          // prettier-ignore
          import {
              AmountDerivationErrors
          } from "../interfaces/AmountDerivationErrors.sol";
          import "./ConsiderationConstants.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 the 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) {
                          mstore(0, InexactFraction_error_signature)
                          revert(0, InexactFraction_error_len)
                      }
                  }
                  // Multiply the numerator by the value and ensure no overflow occurs.
                  uint256 valueTimesNumerator = value * numerator;
                  // Divide and check for remainder. 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.7;
          /**
           * @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.13;
          import { Side, ItemType } from "./ConsiderationEnums.sol";
          // prettier-ignore
          import {
              OfferItem,
              ConsiderationItem,
              ReceivedItem,
              OrderParameters,
              Fulfillment,
              FulfillmentComponent,
              Execution,
              Order,
              AdvancedOrder,
              CriteriaResolver
          } from "./ConsiderationStructs.sol";
          import { OrderFulfiller } from "./OrderFulfiller.sol";
          import { FulfillmentApplier } from "./FulfillmentApplier.sol";
          import "./ConsiderationConstants.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[][] calldata offerFulfillments,
                  FulfillmentComponent[][] calldata considerationFulfillments,
                  bytes32 fulfillerConduitKey,
                  address recipient,
                  uint256 maximumFulfilled
              )
                  internal
                  returns (bool[] memory availableOrders, Execution[] memory executions)
              {
                  // Validate orders, apply amounts, & determine if they utilize conduits.
                  _validateOrdersAndPrepareToFulfill(
                      advancedOrders,
                      criteriaResolvers,
                      false, // Signifies that invalid orders should NOT revert.
                      maximumFulfilled,
                      recipient
                  );
                  // Aggregate used offer and consideration items and execute transfers.
                  (availableOrders, executions) = _executeAvailableFulfillments(
                      advancedOrders,
                      offerFulfillments,
                      considerationFulfillments,
                      fulfillerConduitKey,
                      recipient
                  );
                  // Return order fulfillment details and executions.
                  return (availableOrders, executions);
              }
              /**
               * @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.
               *
               * @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 received items.
               */
              function _validateOrdersAndPrepareToFulfill(
                  AdvancedOrder[] memory advancedOrders,
                  CriteriaResolver[] memory criteriaResolvers,
                  bool revertOnInvalid,
                  uint256 maximumFulfilled,
                  address recipient
              ) internal {
                  // Ensure this function cannot be triggered during a reentrant call.
                  _setReentrancyGuard();
                  // Read length of orders array and place on the stack.
                  uint256 totalOrders = advancedOrders.length;
                  // Track the order hash for each order being fulfilled.
                  bytes32[] memory orderHashes = new bytes32[](totalOrders);
                  // Override orderHashes length to zero after memory has been allocated.
                  assembly {
                      mstore(orderHashes, 0)
                  }
                  // Declare an error buffer indicating status of any native offer items.
                  // {00} == 0 => In a match function, no native offer items: allow.
                  // {01} == 1 => In a match function, some native offer items: allow.
                  // {10} == 2 => Not in a match function, no native offer items: allow.
                  // {11} == 3 => Not in a match function, some native offer items: THROW.
                  uint256 invalidNativeOfferItemErrorBuffer;
                  // Use assembly to set the value for the second bit of the error buffer.
                  assembly {
                      // Use the second bit of the error buffer to indicate whether the
                      // current function is not matchAdvancedOrders or matchOrders.
                      invalidNativeOfferItemErrorBuffer := shl(
                          1,
                          gt(
                              // Take the remainder of the selector modulo a magic value.
                              mod(
                                  shr(NumBitsAfterSelector, calldataload(0)),
                                  NonMatchSelector_MagicModulus
                              ),
                              // Check if remainder is higher than the greatest remainder
                              // of the two match selectors modulo the magic value.
                              NonMatchSelector_MagicRemainder
                          )
                      )
                  }
                  // 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 current order.
                          AdvancedOrder memory advancedOrder = advancedOrders[i];
                          // Determine if max number orders have already been fulfilled.
                          if (maximumFulfilled == 0) {
                              // Mark fill fraction as zero as the order will not be used.
                              advancedOrder.numerator = 0;
                              // Update the length of the orderHashes array.
                              assembly {
                                  mstore(orderHashes, add(i, 1))
                              }
                              // Continue iterating through the remaining orders.
                              continue;
                          }
                          // Validate it, update status, and determine fraction to fill.
                          (
                              bytes32 orderHash,
                              uint256 numerator,
                              uint256 denominator
                          ) = _validateOrderAndUpdateStatus(
                                  advancedOrder,
                                  criteriaResolvers,
                                  revertOnInvalid,
                                  orderHashes
                              );
                          // Update the length of the orderHashes array.
                          assembly {
                              mstore(orderHashes, add(i, 1))
                          }
                          // Do not track hash or adjust prices if order is not fulfilled.
                          if (numerator == 0) {
                              // Mark fill fraction as zero if the order is not fulfilled.
                              advancedOrder.numerator = 0;
                              // Continue iterating through the remaining orders.
                              continue;
                          }
                          // Otherwise, track the order hash in question.
                          orderHashes[i] = orderHash;
                          // Decrement the number of fulfilled orders.
                          // Skip underflow check as the condition before
                          // implies that maximumFulfilled > 0.
                          maximumFulfilled--;
                          // 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;
                          // 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];
                              assembly {
                                  // If the offer item is for the native token, set the
                                  // first bit of the error buffer to true.
                                  invalidNativeOfferItemErrorBuffer := or(
                                      invalidNativeOfferItemErrorBuffer,
                                      iszero(mload(offerItem))
                                  )
                              }
                              // Apply order fill fraction to offer item end amount.
                              uint256 endAmount = _getFraction(
                                  numerator,
                                  denominator,
                                  offerItem.endAmount
                              );
                              // Reuse same fraction if start and end amounts are equal.
                              if (offerItem.startAmount == offerItem.endAmount) {
                                  // Apply derived amount to both start and end amount.
                                  offerItem.startAmount = endAmount;
                              } else {
                                  // Apply order fill fraction to offer item start amount.
                                  offerItem.startAmount = _getFraction(
                                      numerator,
                                      denominator,
                                      offerItem.startAmount
                                  );
                              }
                              // Update end amount in memory to match the derived amount.
                              offerItem.endAmount = endAmount;
                              // Adjust offer amount using current time; round down.
                              offerItem.startAmount = _locateCurrentAmount(
                                  offerItem.startAmount,
                                  offerItem.endAmount,
                                  startTime,
                                  endTime,
                                  false // round down
                              );
                          }
                          // Retrieve array of consideration items for order in question.
                          ConsiderationItem[] memory consideration = (
                              advancedOrder.parameters.consideration
                          );
                          // Read length of consideration array and place on the 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 and end amounts are equal.
                              if (
                                  considerationItem.startAmount ==
                                  considerationItem.endAmount
                              ) {
                                  // Apply derived amount to both start and end amount.
                                  considerationItem.startAmount = endAmount;
                              } else {
                                  // Apply fraction to consideration item start amount.
                                  considerationItem.startAmount = _getFraction(
                                      numerator,
                                      denominator,
                                      considerationItem.startAmount
                                  );
                              }
                              // Update end amount in memory to match the derived amount.
                              considerationItem.endAmount = endAmount;
                              // Adjust consideration amount using current time; round up.
                              considerationItem.startAmount = (
                                  _locateCurrentAmount(
                                      considerationItem.startAmount,
                                      considerationItem.endAmount,
                                      startTime,
                                      endTime,
                                      true // round up
                                  )
                              );
                              // Utilize assembly to manually "shift" the recipient value.
                              assembly {
                                  // 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,
                                          ReceivedItem_recipient_offset // old endAmount
                                      ),
                                      mload(
                                          add(
                                              considerationItem,
                                              ConsiderationItem_recipient_offset
                                          )
                                      )
                                  )
                              }
                          }
                      }
                  }
                  // If the first bit is set, a native offer item was encountered. If the
                  // second bit is set in the error buffer, the current function is not
                  // matchOrders or matchAdvancedOrders. If the value is three, both the
                  // first and second bits were set; in that case, revert with an error.
                  if (invalidNativeOfferItemErrorBuffer == 3) {
                      revert InvalidNativeOfferItem();
                  }
                  // Apply criteria resolvers to each order as applicable.
                  _applyCriteriaResolvers(advancedOrders, criteriaResolvers);
                  // Emit an event for each order signifying that it has been fulfilled.
                  // Skip overflow checks as all for loops are indexed starting at zero.
                  unchecked {
                      // Iterate over each order.
                      for (uint256 i = 0; i < totalOrders; ++i) {
                          // Do not emit an event if no order hash is present.
                          if (orderHashes[i] == bytes32(0)) {
                              continue;
                          }
                          // Retrieve parameters for the order in question.
                          OrderParameters memory orderParameters = (
                              advancedOrders[i].parameters
                          );
                          // Emit an OrderFulfilled event.
                          _emitOrderFulfilledEvent(
                              orderHashes[i],
                              orderParameters.offerer,
                              orderParameters.zone,
                              recipient,
                              orderParameters.offer,
                              orderParameters.consideration
                          );
                      }
                  }
              }
              /**
               * @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 received
               *                                  items.
               *
               * @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
              )
                  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 {
                      // Track number of filtered executions.
                      uint256 totalFilteredExecutions = 0;
                      // Iterate over each offer fulfillment.
                      for (uint256 i = 0; i < totalOfferFulfillments; ++i) {
                          /// Retrieve the offer fulfillment components in question.
                          FulfillmentComponent[] memory components = (
                              offerFulfillments[i]
                          );
                          // Derive aggregated execution corresponding with fulfillment.
                          Execution memory execution = _aggregateAvailable(
                              advancedOrders,
                              Side.OFFER,
                              components,
                              fulfillerConduitKey,
                              recipient
                          );
                          // If offerer and recipient on the execution are the same...
                          if (execution.item.recipient == execution.offerer) {
                              // Increment total filtered executions.
                              ++totalFilteredExecutions;
                          } else {
                              // Otherwise, assign the execution to the executions array.
                              executions[i - totalFilteredExecutions] = execution;
                          }
                      }
                      // Iterate over each consideration fulfillment.
                      for (uint256 i = 0; i < totalConsiderationFulfillments; ++i) {
                          /// Retrieve consideration fulfillment components in question.
                          FulfillmentComponent[] memory components = (
                              considerationFulfillments[i]
                          );
                          // Derive aggregated execution corresponding with fulfillment.
                          Execution memory execution = _aggregateAvailable(
                              advancedOrders,
                              Side.CONSIDERATION,
                              components,
                              fulfillerConduitKey,
                              address(0) // unused
                          );
                          // If offerer and recipient on the execution are the same...
                          if (execution.item.recipient == execution.offerer) {
                              // Increment total filtered executions.
                              ++totalFilteredExecutions;
                          } else {
                              // Otherwise, assign the execution to the executions array.
                              executions[
                                  i + totalOfferFulfillments - totalFilteredExecutions
                              ] = execution;
                          }
                      }
                      // If some number of executions have been filtered...
                      if (totalFilteredExecutions != 0) {
                          // reduce the total length of the executions array.
                          assembly {
                              mstore(
                                  executions,
                                  sub(mload(executions), totalFilteredExecutions)
                              )
                          }
                      }
                  }
                  // Revert if no orders are available.
                  if (executions.length == 0) {
                      revert NoSpecifiedOrdersAvailable();
                  }
                  // Perform final checks and return.
                  availableOrders = _performFinalChecksAndExecuteOrders(
                      advancedOrders,
                      executions
                  );
                  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.
               *
               * @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
              ) 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.
                  availableOrders = new bool[](totalOrders);
                  // Skip overflow checks as all for loops are indexed starting at zero.
                  unchecked {
                      // Iterate over orders to ensure all considerations are met.
                      for (uint256 i = 0; i < totalOrders; ++i) {
                          // Retrieve the order in question.
                          AdvancedOrder memory advancedOrder = advancedOrders[i];
                          // Skip consideration item checks for order if not fulfilled.
                          if (advancedOrder.numerator == 0) {
                              // Note: orders do not need to be marked as unavailable as a
                              // new memory region has been allocated. Review carefully if
                              // altering compiler version or managing memory manually.
                              continue;
                          }
                          // Mark the order as available.
                          availableOrders[i] = true;
                          // Retrieve consideration items to ensure they are fulfilled.
                          ConsiderationItem[] memory consideration = (
                              advancedOrder.parameters.consideration
                          );
                          // Read length of consideration array and place on the stack.
                          uint256 totalConsiderationItems = consideration.length;
                          // Iterate over each consideration item to ensure it is met.
                          for (uint256 j = 0; j < totalConsiderationItems; ++j) {
                              // Retrieve remaining amount on the consideration item.
                              uint256 unmetAmount = consideration[j].startAmount;
                              // Revert if the remaining amount is not zero.
                              if (unmetAmount != 0) {
                                  revert ConsiderationNotMet(i, j, unmetAmount);
                              }
                          }
                      }
                  }
                  // Put ether value supplied by the caller on the stack.
                  uint256 etherRemaining = msg.value;
                  // 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);
                  // Retrieve the length of the executions array and place on stack.
                  uint256 totalExecutions = executions.length;
                  // Iterate over each execution.
                  for (uint256 i = 0; i < totalExecutions; ) {
                      // Retrieve the execution and the associated received item.
                      Execution memory execution = executions[i];
                      ReceivedItem memory item = execution.item;
                      // If execution transfers native tokens, reduce value available.
                      if (item.itemType == ItemType.NATIVE) {
                          // Ensure that sufficient native tokens are still available.
                          if (item.amount > etherRemaining) {
                              revert InsufficientEtherSupplied();
                          }
                          // Skip underflow check as amount is less than ether remaining.
                          unchecked {
                              etherRemaining -= item.amount;
                          }
                      }
                      // Transfer the item specified by the execution.
                      _transfer(
                          item,
                          execution.offerer,
                          execution.conduitKey,
                          accumulator
                      );
                      // Skip overflow check as for loop is indexed starting at zero.
                      unchecked {
                          ++i;
                      }
                  }
                  // Trigger any remaining accumulated transfers via call to the conduit.
                  _triggerIfArmed(accumulator);
                  // If any ether remains after fulfillments, return it to the caller.
                  if (etherRemaining != 0) {
                      _transferEth(payable(msg.sender), etherRemaining);
                  }
                  // Clear the reentrancy guard.
                  _clearReentrancyGuard();
                  // Return the array containing available orders.
                  return (availableOrders);
              }
              /**
               * @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.
               *
               * @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[] calldata fulfillments
              ) internal returns (Execution[] memory executions) {
                  // Validate orders, update order status, and determine item amounts.
                  _validateOrdersAndPrepareToFulfill(
                      advancedOrders,
                      criteriaResolvers,
                      true, // Signifies that invalid orders should revert.
                      advancedOrders.length,
                      address(0) // OrderFulfilled event has no recipient when matching.
                  );
                  // Fulfill the orders using the supplied fulfillments.
                  return _fulfillAdvancedOrders(advancedOrders, fulfillments);
              }
              /**
               * @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.
               *
               * @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[] calldata fulfillments
              ) 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 {
                      // Track number of filtered executions.
                      uint256 totalFilteredExecutions = 0;
                      // Iterate over each fulfillment.
                      for (uint256 i = 0; i < totalFulfillments; ++i) {
                          /// Retrieve the fulfillment in question.
                          Fulfillment calldata fulfillment = fulfillments[i];
                          // Derive the execution corresponding with the fulfillment.
                          Execution memory execution = _applyFulfillment(
                              advancedOrders,
                              fulfillment.offerComponents,
                              fulfillment.considerationComponents
                          );
                          // If offerer and recipient on the execution are the same...
                          if (execution.item.recipient == execution.offerer) {
                              // Increment total filtered executions.
                              ++totalFilteredExecutions;
                          } else {
                              // Otherwise, assign the execution to the executions array.
                              executions[i - totalFilteredExecutions] = execution;
                          }
                      }
                      // If some number of executions have been filtered...
                      if (totalFilteredExecutions != 0) {
                          // reduce the total length of the executions array.
                          assembly {
                              mstore(
                                  executions,
                                  sub(mload(executions), totalFilteredExecutions)
                              )
                          }
                      }
                  }
                  // Perform final checks and execute orders.
                  _performFinalChecksAndExecuteOrders(advancedOrders, executions);
                  // Return the executions array.
                  return (executions);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.13;
          // prettier-ignore
          import {
              ConsiderationInterface
          } from "../interfaces/ConsiderationInterface.sol";
          // prettier-ignore
          import {
              OrderComponents,
              BasicOrderParameters,
              OrderParameters,
              Order,
              AdvancedOrder,
              OrderStatus,
              CriteriaResolver,
              Fulfillment,
              FulfillmentComponent,
              Execution
          } from "./ConsiderationStructs.sol";
          import { OrderCombiner } from "./OrderCombiner.sol";
          /**
           * @title Consideration
           * @author 0age
           * @custom:coauthor d1ll0n
           * @custom:coauthor transmissions11
           * @custom:version 1.1
           * @notice Consideration is a generalized ETH/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 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 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.
               *
               * @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` in order to receive those
               *                   items.
               *
               * @return fulfilled A boolean indicating whether the order has been
               *                   successfully fulfilled.
               */
              function fulfillBasicOrder(BasicOrderParameters calldata parameters)
                  external
                  payable
                  override
                  returns (bool fulfilled)
              {
                  // Validate and fulfill the basic order.
                  fulfilled = _validateAndFulfillBasicOrder(parameters);
              }
              /**
               * @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 (and 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
                  override
                  returns (bool fulfilled)
              {
                  // Convert order to "advanced" order, then validate and fulfill it.
                  fulfilled = _validateAndFulfillAdvancedOrder(
                      _convertOrderToAdvanced(order),
                      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.
               *
               * @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.
               * @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
               *                            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 override returns (bool fulfilled) {
                  // Validate and fulfill the order.
                  fulfilled = _validateAndFulfillAdvancedOrder(
                      advancedOrder,
                      criteriaResolvers,
                      fulfillerConduitKey,
                      recipient == address(0) ? msg.sender : 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).
               *
               * @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 (and
               *                                  direct approvals set on Consideration).
               * @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(
                  Order[] calldata orders,
                  FulfillmentComponent[][] calldata offerFulfillments,
                  FulfillmentComponent[][] calldata considerationFulfillments,
                  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(
                          _convertOrdersToAdvanced(orders), // Convert to advanced orders.
                          new CriteriaResolver[](0), // No criteria resolvers supplied.
                          offerFulfillments,
                          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.
               *
               * @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` 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, 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.
               */
              function fulfillAvailableAdvancedOrders(
                  AdvancedOrder[] memory advancedOrders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  FulfillmentComponent[][] calldata offerFulfillments,
                  FulfillmentComponent[][] calldata considerationFulfillments,
                  bytes32 fulfillerConduitKey,
                  address recipient,
                  uint256 maximumFulfilled
              )
                  external
                  payable
                  override
                  returns (bool[] memory availableOrders, Execution[] memory executions)
              {
                  // Fulfill all available orders.
                  return
                      _fulfillAvailableAdvancedOrders(
                          advancedOrders,
                          criteriaResolvers,
                          offerFulfillments,
                          considerationFulfillments,
                          fulfillerConduitKey,
                          recipient == address(0) ? msg.sender : 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).
               *
               * @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` in order to
               *                          receive ERC1155 tokens.
               * @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.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function matchOrders(
                  Order[] calldata orders,
                  Fulfillment[] calldata fulfillments
              ) external payable override returns (Execution[] memory executions) {
                  // Convert to advanced, validate, and match orders using fulfillments.
                  return
                      _matchAdvancedOrders(
                          _convertOrdersToAdvanced(orders),
                          new CriteriaResolver[](0), // No criteria resolvers supplied.
                          fulfillments
                      );
              }
              /**
               * @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.
               *
               * @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.
               *
               * @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[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              ) external payable override returns (Execution[] memory executions) {
                  // Validate and match the advanced orders using supplied fulfillments.
                  return
                      _matchAdvancedOrders(
                          advancedOrders,
                          criteriaResolvers,
                          fulfillments
                      );
              }
              /**
               * @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.
               *
               * @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
                  override
                  returns (bool validated)
              {
                  // Validate the orders.
                  validated = _validate(orders);
              }
              /**
               * @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.
                  newCounter = _incrementCounter();
              }
              /**
               * @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
                  override
                  returns (bytes32 orderHash)
              {
                  // Derive order hash by supplying order parameters along with counter.
                  orderHash = _deriveOrderHash(
                      OrderParameters(
                          order.offerer,
                          order.zone,
                          order.offer,
                          order.consideration,
                          order.orderType,
                          order.startTime,
                          order.endTime,
                          order.zoneHash,
                          order.salt,
                          order.conduitKey,
                          order.consideration.length
                      ),
                      order.counter
                  );
              }
              /**
               * @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
                  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();
              }
              /**
               * @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.
                  contractName = _name();
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              BasicOrderParameters,
              OrderComponents,
              Fulfillment,
              FulfillmentComponent,
              Execution,
              Order,
              AdvancedOrder,
              OrderStatus,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          /**
           * @title ConsiderationInterface
           * @author 0age
           * @custom:version 1.1
           * @notice Consideration is a generalized ETH/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.
               */
              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.
               */
              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 as 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).
               *
               * @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.
               */
              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.
               *
               * @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.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function matchAdvancedOrders(
                  AdvancedOrder[] calldata orders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              ) 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 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
                  );
              /**
               * @notice Retrieve the name of this contract.
               *
               * @return contractName The name of this contract.
               */
              function name() external view returns (string memory contractName);
          }
          

          File 2 of 7: NyanBall
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @title: Nyan Balloon
          /// @author: manifold.xyz
          import "./manifold/ERC1155Creator.sol";
          ///////////////////////////////////////////////////////////////////////////////////////////////////////////
          //                                                                                                       //
          //                                                                                                       //
          //                ████████                                                                               //
          //            ████▒▒▒▒▒▒▒▒████                                                                           //
          //          ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                         //
          //        ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                       //
          //        ██▒▒▒▒▒▒▒▒▒▒▒▒░░░░▒▒▒▒██                                                                       //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒    ▒▒▒▒██                                                                     //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░  ▒▒▒▒██                                                                     //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▒▒██                                                                     //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                     //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                     //
          //      ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                     //
          //        ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                       //
          //        ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                       //
          //          ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██                                                                         //
          //            ████▒▒▒▒▒▒▒▒████                                                                           //
          //                ██▒▒▒▒██                                                                               //
          //                  ████                                                                                 //
          //                ██▒▒▒▒██                                                                               //
          //                ████████                                                                               //
          //                  ██                                                                                   //
          //                  ██                                                                                   //
          //                  ██                                                                                   //
          //                  ██                                                                                   //
          //                  ██                                                                                   //
          //                  ██      ████                ████                                                     //
          //                  ██    ██▒▒▒▒██            ██▒▒▒▒██                                                   //
          //                  ██    ██░░░░▒▒██        ██░░░░░░██                                                   //
          //                  ██    ██░░░░░░░░████████░░░░░░░░██                                                   //
          //                  ██    ██░░░░░░░░░░░░░░░░░░░░░░░░██                                                   //
          //                  ██  ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░██                                                 //
          //                ██    ██░░░░░░  ██░░░░░░░░░░  ██░░░░██                                                 //
          //                ██    ██░░░░░░████░░░░░░██░░████░░░░██                                                 //
          //                ██    ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░██                                                 //
          //                ██    ██░░░░░░░░██░░░░██░░░░██░░░░░░██                                                 //
          //                ██  ██░░██░░░░░░██████████████░░░░██                                                   //
          //                ██  ██░░░░██░░░░░░░░░░░░░░░░░░░░██                                                     //
          //                ████░░░░░░░░████████████████████                                                       //
          //                  ████░░░░░░░░░░██░░░░░░░░░░░░██                                                       //
          //      ████████  ██░░░░████░░░░░░██░░░░██░░░░░░██                                                       //
          //      ██▒▒▒▒██  ██░░░░▒▒▒▒██░░░░██░░██  ██░░░░██                                                       //
          //      ████░░▒▒████░░░░░░░░██░░░░██░░██  ██░░░░██                                                       //
          //        ████░░░░██░░░░░░░░██░░░░██░░██  ██░░░░██                                                       //
          //          ████░░██░░░░░░░░░░██████░░██    ████                                                         //
          //            ██████░░░░░░░░░░▒▒▒▒▒▒░░██                                                                 //
          //                  ██░░░░░░░░░░░░░░░░██                                                                 //
          //                  ██░░░░░░██████░░░░██                                                                 //
          //                  ██░░░░██░░░░██░░░░██                                                                 //
          //                  ██░░░░██    ██░░░░██                                                                 //
          //                  ██░░░░██    ██░░░░██                                                                 //
          //                    ████        ████                                                                   //
          //                                                                                                       //
          //    Balloon Cat is a character I personally created back in October 2011 that                          //
          //    was originally meant to serve as a backstory to a certain space cat.                               //
          //    Ultimately, I ultimately felt this idea should be unique to the person that                        //
          //    imagines it. This piece has been digitally remastered for 2023 and                                 //
          //    I hope it's enjoyed by everyone who collects it ✨🎈                                                //
          //                                                                                                       //
          //    You may view the original video here:                                                              //
          //    https://www.youtube.com/watch?v=In1IKpcviIc                                                        //
          //                                                                                                       //
          //                                                                                                       //
          //                                                                                                       //
          ///////////////////////////////////////////////////////////////////////////////////////////////////////////
          contract NyanBall is ERC1155Creator {
              constructor() ERC1155Creator("Nyan Balloon", "NyanBall") {}
          }
          
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/proxy/Proxy.sol";
          import "@openzeppelin/contracts/utils/Address.sol";
          import "@openzeppelin/contracts/utils/StorageSlot.sol";
          contract ERC1155Creator is Proxy {
              constructor(string memory name, string memory symbol) {
                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = 0x6bf5ed59dE0E19999d264746843FF931c0133090;
                  Address.functionDelegateCall(
                      0x6bf5ed59dE0E19999d264746843FF931c0133090,
                      abi.encodeWithSignature("initialize(string,string)", name, symbol)
                  );
              }
              /**
               * @dev Storage slot with the address of the current implementation.
               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
              /**
               * @dev Returns the current implementation address.
               */
               function implementation() public view returns (address) {
                  return _implementation();
              }
              function _implementation() internal override view returns (address) {
                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
              }    
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
           * be specified by overriding the virtual {_implementation} function.
           *
           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
           * different contract through the {_delegate} function.
           *
           * The success and return data of the delegated call will be returned back to the caller of the proxy.
           */
          abstract contract Proxy {
              /**
               * @dev Delegates the current call to `implementation`.
               *
               * This function does not return to its internal call site, it will return directly to the external caller.
               */
              function _delegate(address implementation) internal virtual {
                  assembly {
                      // Copy msg.data. We take full control of memory in this inline assembly
                      // block because it will not return to Solidity code. We overwrite the
                      // Solidity scratch pad at memory position 0.
                      calldatacopy(0, 0, calldatasize())
                      // Call the implementation.
                      // out and outsize are 0 because we don't know the size yet.
                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                      // Copy the returned data.
                      returndatacopy(0, 0, returndatasize())
                      switch result
                      // delegatecall returns 0 on error.
                      case 0 {
                          revert(0, returndatasize())
                      }
                      default {
                          return(0, returndatasize())
                      }
                  }
              }
              /**
               * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
               * and {_fallback} should delegate.
               */
              function _implementation() internal view virtual returns (address);
              /**
               * @dev Delegates the current call to the address returned by `_implementation()`.
               *
               * This function does not return to its internal call site, it will return directly to the external caller.
               */
              function _fallback() internal virtual {
                  _beforeFallback();
                  _delegate(_implementation());
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
               * function in the contract matches the call data.
               */
              fallback() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
               * is empty.
               */
              receive() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
               * call, or as part of the Solidity `fallback` or `receive` functions.
               *
               * If overridden should call `super._beforeFallback()`.
               */
              function _beforeFallback() internal virtual {}
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.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
                  }
              }
          }
          

          File 3 of 7: PausableZone
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
          import { ZoneInteractionErrors } from "../interfaces/ZoneInteractionErrors.sol";
          // prettier-ignore
          import {
              PausableZoneEventsAndErrors
          } from "./interfaces/PausableZoneEventsAndErrors.sol";
          import { SeaportInterface } from "../interfaces/SeaportInterface.sol";
          // prettier-ignore
          import {
              AdvancedOrder,
              CriteriaResolver,
              Order,
              OrderComponents,
              Fulfillment,
              Execution
          } from "../lib/ConsiderationStructs.sol";
          import { PausableZoneInterface } from "./interfaces/PausableZoneInterface.sol";
          /**
           * @title  PausableZone
           * @author cupOJoseph, BCLeFevre, ryanio
           * @notice PausableZone is a simple zone implementation that approves every
           *         order. It can be self-destructed by its controller to pause
           *         restricted orders that have it set as their zone.
           */
          contract PausableZone is
              PausableZoneEventsAndErrors,
              ZoneInterface,
              PausableZoneInterface
          {
              // Set an immutable controller that can pause the zone & update an operator.
              address internal immutable _controller;
              // Set an operator that can instruct the zone to cancel or execute orders.
              address public operator;
              /**
               * @dev Ensure that the caller is either the operator or controller.
               */
              modifier isOperator() {
                  // Ensure that the caller is either the operator or the controller.
                  if (msg.sender != operator && msg.sender != _controller) {
                      revert InvalidOperator();
                  }
                  // Continue with function execution.
                  _;
              }
              /**
               * @dev Ensure that the caller is the controller.
               */
              modifier isController() {
                  // Ensure that the caller is the controller.
                  if (msg.sender != _controller) {
                      revert InvalidController();
                  }
                  // Continue with function execution.
                  _;
              }
              /**
               * @notice Set the deployer as the controller of the zone.
               */
              constructor() {
                  // Set the controller to the deployer.
                  _controller = msg.sender;
                  // Emit an event signifying that the zone is unpaused.
                  emit Unpaused();
              }
              /**
               * @notice Check if a given order is currently valid.
               *
               * @dev This function is called by Seaport whenever extraData is not
               *      provided by the caller.
               *
               * @param orderHash The hash of the order.
               * @param caller    The caller in question.
               * @param offerer   The offerer in question.
               * @param zoneHash  The hash to provide upon calling the zone.
               *
               * @return validOrderMagicValue A magic value indicating if the order is
               *                              currently valid.
               */
              function isValidOrder(
                  bytes32 orderHash,
                  address caller,
                  address offerer,
                  bytes32 zoneHash
              ) external pure override returns (bytes4 validOrderMagicValue) {
                  orderHash;
                  caller;
                  offerer;
                  zoneHash;
                  // Return the selector of isValidOrder as the magic value.
                  validOrderMagicValue = ZoneInterface.isValidOrder.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.
               *
               * @param orderHash         The hash of the order.
               * @param caller            The caller in question.
               * @param order             The order in question.
               * @param priorOrderHashes  The order hashes of each order supplied prior to
               *                          the current order as part of a "match" variety
               *                          of order fulfillment.
               * @param criteriaResolvers The criteria resolvers corresponding to
               *                          the order.
               *
               * @return validOrderMagicValue A magic value indicating if the order is
               *                              currently valid.
               */
              function isValidOrderIncludingExtraData(
                  bytes32 orderHash,
                  address caller,
                  AdvancedOrder calldata order,
                  bytes32[] calldata priorOrderHashes,
                  CriteriaResolver[] calldata criteriaResolvers
              ) external pure override returns (bytes4 validOrderMagicValue) {
                  orderHash;
                  caller;
                  order;
                  priorOrderHashes;
                  criteriaResolvers;
                  // Return the selector of isValidOrder as the magic value.
                  validOrderMagicValue = ZoneInterface.isValidOrder.selector;
              }
              /**
               * @notice Cancel an arbitrary number of orders that have agreed to use the
               *         contract as their zone.
               *
               * @param seaport  The Seaport address.
               * @param orders   The orders to cancel.
               *
               * @return cancelled A boolean indicating whether the supplied orders have
               *                   been successfully cancelled.
               */
              function cancelOrders(
                  SeaportInterface seaport,
                  OrderComponents[] calldata orders
              ) external override isOperator returns (bool cancelled) {
                  // Call cancel on Seaport and return its boolean value.
                  cancelled = seaport.cancel(orders);
              }
              /**
               * @notice Execute an arbitrary number of matched orders, each with
               *         an arbitrary number of items for offer and consideration
               *         along with a set of fulfillments allocating offer components
               *         to consideration components.
               *
               * @param seaport      The Seaport address.
               * @param orders       The orders to match.
               * @param fulfillments An array of elements allocating offer components
               *                     to consideration components.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function executeMatchOrders(
                  SeaportInterface seaport,
                  Order[] calldata orders,
                  Fulfillment[] calldata fulfillments
              )
                  external
                  payable
                  override
                  isOperator
                  returns (Execution[] memory executions)
              {
                  // Call matchOrders on Seaport and return the sequence of transfers
                  // performed as part of matching the given orders.
                  executions = seaport.matchOrders{ value: msg.value }(
                      orders,
                      fulfillments
                  );
              }
              /**
               * @notice Execute an arbitrary number of matched advanced orders,
               *         each with an arbitrary number of items for offer and
               *         consideration along with a set of fulfillments allocating
               *         offer components to consideration components.
               *
               * @param seaport           The Seaport address.
               * @param orders            The orders to match.
               * @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.
               * @param fulfillments      An array of elements allocating offer components
               *                          to consideration components.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function executeMatchAdvancedOrders(
                  SeaportInterface seaport,
                  AdvancedOrder[] calldata orders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              )
                  external
                  payable
                  override
                  isOperator
                  returns (Execution[] memory executions)
              {
                  // Call matchAdvancedOrders on Seaport and return the sequence of
                  // transfers performed as part of matching the given orders.
                  executions = seaport.matchAdvancedOrders{ value: msg.value }(
                      orders,
                      criteriaResolvers,
                      fulfillments
                  );
              }
              /**
               * @notice Pause this contract, safely stopping orders from using
               *         the contract as a zone. Restricted orders with this address as a
               *         zone will not be fulfillable unless the zone is redeployed to the
               *         same address.
               */
              function pause() external override isController {
                  // Emit an event signifying that the zone is paused.
                  emit Paused();
                  // Destroy the zone, sending any ether to the transaction submitter.
                  selfdestruct(payable(tx.origin));
              }
              /**
               * @notice Assign the given address with the ability to operate the zone.
               *
               * @param operatorToAssign The address to assign as the operator.
               */
              function assignOperator(address operatorToAssign)
                  external
                  override
                  isController
              {
                  // Ensure the operator being assigned is not the null address.
                  require(
                      operatorToAssign != address(0),
                      "Operator can not be set to the null address"
                  );
                  // Set the given address as the new operator.
                  operator = operatorToAssign;
                  // Emit an event indicating the operator has been updated.
                  emit OperatorUpdated(operator);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              AdvancedOrder,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          interface ZoneInterface {
              /**
               * @dev Emit an event whenever a zone is successfully paused.
               */
              event Paused();
              /**
               * @dev Emit an event whenever a zone is successfully unpaused (created).
               */
              event Unpaused();
              // Called by Consideration whenever extraData is not provided by the caller.
              function isValidOrder(
                  bytes32 orderHash,
                  address caller,
                  address offerer,
                  bytes32 zoneHash
              ) external view returns (bytes4 validOrderMagicValue);
              // Called by Consideration whenever any extraData is provided by the caller.
              function isValidOrderIncludingExtraData(
                  bytes32 orderHash,
                  address caller,
                  AdvancedOrder calldata order,
                  bytes32[] calldata priorOrderHashes,
                  CriteriaResolver[] calldata criteriaResolvers
              ) external view returns (bytes4 validOrderMagicValue);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @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 staticcall to `isValidOrder`.
               *
               * @param orderHash The order hash for the invalid restricted order.
               */
              error InvalidRestrictedOrder(bytes32 orderHash);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          /**
           * @notice PausableZoneEventsAndErrors contains errors and events
           *         related to zone interaction.
           */
          interface PausableZoneEventsAndErrors {
              /**
               * @dev Emit an event whenever a zone owner registers a new potential
               *      owner for that zone.
               *
               * @param newPotentialOwner The new potential owner of the zone.
               */
              event PotentialOwnerUpdated(address newPotentialOwner);
              /**
               * @dev Emit an event whenever zone ownership is transferred.
               *
               * @param previousOwner The previous owner of the zone.
               * @param newOwner      The new owner of the zone.
               */
              event OwnershipTransferred(address previousOwner, address newOwner);
              /**
               * @dev Emit an event whenever a new zone is created.
               *
               * @param zone The address of the zone.
               * @param salt The salt used to deploy the zone.
               */
              event ZoneCreated(address zone, bytes32 salt);
              /**
               * @dev Emit an event whenever a zone owner assigns a new pauser
               *
               * @param newPauser The new pausear of the zone.
               */
              event PauserUpdated(address newPauser);
              /**
               * @dev Emit an event whenever a zone owner assigns a new operator
               *
               * @param newOperator The new operator of the zone.
               */
              event OperatorUpdated(address newOperator);
              /**
               * @dev Revert with an error when attempting to pause the zone
               *      while the caller is not the owner or pauser of the zone.
               */
              error InvalidPauser();
              /**
               * @dev Revert with an error when attempting to call an operation
               *      while the caller is not the controller or operator of the zone.
               */
              error InvalidOperator();
              /**
               * @dev Revert with an error when attempting to pause the zone or update the
               *      operator while the caller is not the controller of the zone.
               */
              error InvalidController();
              /**
               * @dev Revert with an error when attempting to deploy a zone that is
               *      currently deployed.
               */
              error ZoneAlreadyExists(address zone);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          import {
              BasicOrderParameters,
              OrderComponents,
              Fulfillment,
              FulfillmentComponent,
              Execution,
              Order,
              AdvancedOrder,
              OrderStatus,
              CriteriaResolver
          } from "../lib/ConsiderationStructs.sol";
          /**
           * @title SeaportInterface
           * @author 0age
           * @custom:version 1.1
           * @notice Seaport is a generalized ETH/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 SeaportInterface contains all external function interfaces for Seaport.
           */
          interface SeaportInterface {
              /**
               * @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
               *                            Seaport.
               *
               * @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
               *                            Seaport.
               * @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.
               */
              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.
               */
              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 as 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).
               *
               * @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.
               */
              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.
               *
               * @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.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function matchAdvancedOrders(
                  AdvancedOrder[] calldata orders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              ) 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 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
                  );
              /**
               * @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.7;
          // prettier-ignore
          import {
              OrderType,
              BasicOrderType,
              ItemType,
              Side
          } from "./ConsiderationEnums.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 included in a staticcall to
           *      `isValidOrderIncludingExtraData` on the zone for the order if the order
           *      type is restricted and the offerer or zone are not the caller.
           */
          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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          import { SeaportInterface } from "../../interfaces/SeaportInterface.sol";
          // prettier-ignore
          import {
              AdvancedOrder,
              CriteriaResolver,
              Order,
              OrderComponents,
              Fulfillment,
              Execution
          } from "../../lib/ConsiderationStructs.sol";
          /**
           * @title  PausableZone
           * @author cupOJoseph, BCLeFevre, ryanio
           * @notice PausableZone is a simple zone implementation that approves every
           *         order. It can be self-destructed by its controller to pause
           *         restricted orders that have it set as their zone.
           */
          interface PausableZoneInterface {
              /**
               * @notice Cancel an arbitrary number of orders that have agreed to use the
               *         contract as their zone.
               *
               * @param seaport  The Seaport address.
               * @param orders   The orders to cancel.
               *
               * @return cancelled A boolean indicating whether the supplied orders have
               *                   been successfully cancelled.
               */
              function cancelOrders(
                  SeaportInterface seaport,
                  OrderComponents[] calldata orders
              ) external returns (bool cancelled);
              /**
               * @notice Execute an arbitrary number of matched orders, each with
               *         an arbitrary number of items for offer and consideration
               *         along with a set of fulfillments allocating offer components
               *         to consideration components.
               *
               * @param seaport      The Seaport address.
               * @param orders       The orders to match.
               * @param fulfillments An array of elements allocating offer components
               *                     to consideration components.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function executeMatchOrders(
                  SeaportInterface seaport,
                  Order[] calldata orders,
                  Fulfillment[] calldata fulfillments
              ) external payable returns (Execution[] memory executions);
              /**
               * @notice Execute an arbitrary number of matched advanced orders,
               *         each with an arbitrary number of items for offer and
               *         consideration along with a set of fulfillments allocating
               *         offer components to consideration components.
               *
               * @param seaport           The Seaport address.
               * @param orders            The orders to match.
               * @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.
               * @param fulfillments      An array of elements allocating offer components
               *                          to consideration components.
               *
               * @return executions An array of elements indicating the sequence of
               *                    transfers performed as part of matching the given
               *                    orders.
               */
              function executeMatchAdvancedOrders(
                  SeaportInterface seaport,
                  AdvancedOrder[] calldata orders,
                  CriteriaResolver[] calldata criteriaResolvers,
                  Fulfillment[] calldata fulfillments
              ) external payable returns (Execution[] memory executions);
              /**
               * @notice Pause this contract, safely stopping orders from using
               *         the contract as a zone. Restricted orders with this address as a
               *         zone will not be fulfillable unless the zone is redeployed to the
               *         same address.
               */
              function pause() external;
              /**
               * @notice Assign the given address with the ability to operate the zone.
               *
               * @param operatorToAssign The address to assign as the operator.
               */
              function assignOperator(address operatorToAssign) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.8.7;
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          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
          }
          // prettier-ignore
          enum Side {
              // 0: Items that can be spent
              OFFER,
              // 1: Items that must be received
              CONSIDERATION
          }
          

          File 4 of 7: 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;
          }
          

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

          File 6 of 7: ERC1155CreatorImplementation
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
          import "@manifoldxyz/libraries-solidity/contracts/access/AdminControlUpgradeable.sol";
          import "./core/ERC1155CreatorCore.sol";
          /**
           * @dev ERC1155Creator implementation
           */
          contract ERC1155CreatorImplementation is AdminControlUpgradeable, ERC1155Upgradeable, ERC1155CreatorCore {
              mapping(uint256 => uint256) private _totalSupply;
              /**
               * Initializer
               */
              function initialize(string memory _name, string memory _symbol) public initializer {
                  __ERC1155_init("");
                  __Ownable_init();
                  name = _name;
                  symbol = _symbol;
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155Upgradeable, ERC1155CreatorCore, AdminControlUpgradeable) returns (bool) {
                  return ERC1155CreatorCore.supportsInterface(interfaceId) || ERC1155Upgradeable.supportsInterface(interfaceId) || AdminControlUpgradeable.supportsInterface(interfaceId);
              }
              function _beforeTokenTransfer(address, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory) internal virtual override {
                  _approveTransfer(from, to, ids, amounts);
              }
              /**
               * @dev See {ICreatorCore-registerExtension}.
               */
              function registerExtension(address extension, string calldata baseURI) external override adminRequired {
                  requireNonBlacklist(extension);
                  _registerExtension(extension, baseURI, false);
              }
              /**
               * @dev See {ICreatorCore-registerExtension}.
               */
              function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external override adminRequired {
                  requireNonBlacklist(extension);
                  _registerExtension(extension, baseURI, baseURIIdentical);
              }
              /**
               * @dev See {ICreatorCore-unregisterExtension}.
               */
              function unregisterExtension(address extension) external override adminRequired {
                  _unregisterExtension(extension);
              }
              /**
               * @dev See {ICreatorCore-blacklistExtension}.
               */
              function blacklistExtension(address extension) external override adminRequired {
                  _blacklistExtension(extension);
              }
              /**
               * @dev See {ICreatorCore-setBaseTokenURIExtension}.
               */
              function setBaseTokenURIExtension(string calldata uri_) external override {
                  requireExtension();
                  _setBaseTokenURIExtension(uri_, false);
              }
              /**
               * @dev See {ICreatorCore-setBaseTokenURIExtension}.
               */
              function setBaseTokenURIExtension(string calldata uri_, bool identical) external override {
                  requireExtension();
                  _setBaseTokenURIExtension(uri_, identical);
              }
              /**
               * @dev See {ICreatorCore-setTokenURIPrefixExtension}.
               */
              function setTokenURIPrefixExtension(string calldata prefix) external override {
                  requireExtension();
                  _setTokenURIPrefixExtension(prefix);
              }
              /**
               * @dev See {ICreatorCore-setTokenURIExtension}.
               */
              function setTokenURIExtension(uint256 tokenId, string calldata uri_) external override {
                  requireExtension();
                  _setTokenURIExtension(tokenId, uri_);
              }
              /**
               * @dev See {ICreatorCore-setTokenURIExtension}.
               */
              function setTokenURIExtension(uint256[] memory tokenIds, string[] calldata uris) external override {
                  requireExtension();
                  require(tokenIds.length == uris.length, "Invalid input");
                  for (uint i; i < tokenIds.length;) {
                      _setTokenURIExtension(tokenIds[i], uris[i]);
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev See {ICreatorCore-setBaseTokenURI}.
               */
              function setBaseTokenURI(string calldata uri_) external override adminRequired {
                  _setBaseTokenURI(uri_);
              }
              /**
               * @dev See {ICreatorCore-setTokenURIPrefix}.
               */
              function setTokenURIPrefix(string calldata prefix) external override adminRequired {
                  _setTokenURIPrefix(prefix);
              }
              /**
               * @dev See {ICreatorCore-setTokenURI}.
               */
              function setTokenURI(uint256 tokenId, string calldata uri_) external override adminRequired {
                  _setTokenURI(tokenId, uri_);
              }
              /**
               * @dev See {ICreatorCore-setTokenURI}.
               */
              function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external override adminRequired {
                  require(tokenIds.length == uris.length, "Invalid input");
                  for (uint i; i < tokenIds.length;) {
                      _setTokenURI(tokenIds[i], uris[i]);
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev See {ICreatorCore-setMintPermissions}.
               */
              function setMintPermissions(address extension, address permissions) external override adminRequired {
                  _setMintPermissions(extension, permissions);
              }
              /**
               * @dev See {IERC1155CreatorCore-mintBaseNew}.
               */
              function mintBaseNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) public virtual override nonReentrant adminRequired returns(uint256[] memory) {
                  return _mintNew(address(0), to, amounts, uris);
              }
              /**
               * @dev See {IERC1155CreatorCore-mintBaseExisting}.
               */
              function mintBaseExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) public virtual override nonReentrant adminRequired {
                  for (uint i; i < tokenIds.length;) {
                      uint256 tokenId = tokenIds[i];
                      require(tokenId > 0 && tokenId <= _tokenCount, "Invalid token");
                      require(_tokensExtension[tokenId] == address(0), "Token created by extension");
                      unchecked { ++i; }
                  }
                  _mintExisting(address(0), to, tokenIds, amounts);
              }
              /**
               * @dev See {IERC1155CreatorCore-mintExtensionNew}.
               */
              function mintExtensionNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) public virtual override nonReentrant returns(uint256[] memory tokenIds) {
                  requireExtension();
                  return _mintNew(msg.sender, to, amounts, uris);
              }
              /**
               * @dev See {IERC1155CreatorCore-mintExtensionExisting}.
               */
              function mintExtensionExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) public virtual override nonReentrant {
                  requireExtension();
                  for (uint i; i < tokenIds.length;) {
                      require(_tokensExtension[tokenIds[i]] == address(msg.sender), "Token not created by this extension");
                      unchecked { ++i; }
                  }
                  _mintExisting(msg.sender, to, tokenIds, amounts);
              }
              /**
               * @dev Mint new tokens
               */
              function _mintNew(address extension, address[] memory to, uint256[] memory amounts, string[] memory uris) internal returns(uint256[] memory tokenIds) {
                  if (to.length > 1) {
                      // Multiple receiver.  Give every receiver the same new token
                      tokenIds = new uint256[](1);
                      require(uris.length <= 1 && (amounts.length == 1 || to.length == amounts.length), "Invalid input");
                  } else {
                      // Single receiver.  Generating multiple tokens
                      tokenIds = new uint256[](amounts.length);
                      require(uris.length == 0 || amounts.length == uris.length, "Invalid input");
                  }
                  // Assign tokenIds
                  for (uint i; i < tokenIds.length;) {
                      ++_tokenCount;
                      tokenIds[i] = _tokenCount;
                      // Track the extension that minted the token
                      _tokensExtension[_tokenCount] = extension;
                      unchecked { ++i; }
                  }
                  if (extension != address(0)) {
                      _checkMintPermissions(to, tokenIds, amounts);
                  }
                  if (to.length == 1 && tokenIds.length == 1) {
                     // Single mint
                     _mint(to[0], tokenIds[0], amounts[0], new bytes(0));
                  } else if (to.length > 1) {
                      // Multiple receivers.  Receiving the same token
                      if (amounts.length == 1) {
                          // Everyone receiving the same amount
                          for (uint i; i < to.length;) {
                              _mint(to[i], tokenIds[0], amounts[0], new bytes(0));
                              unchecked { ++i; }
                          }
                      } else {
                          // Everyone receiving different amounts
                          for (uint i; i < to.length;) {
                              _mint(to[i], tokenIds[0], amounts[i], new bytes(0));
                              unchecked { ++i; }
                          }
                      }
                  } else {
                      _mintBatch(to[0], tokenIds, amounts, new bytes(0));
                  }
                  for (uint i; i < tokenIds.length;) {
                      if (i < uris.length && bytes(uris[i]).length > 0) {
                          _tokenURIs[tokenIds[i]] = uris[i];
                      }
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev Mint existing tokens
               */
              function _mintExisting(address extension, address[] memory to, uint256[] memory tokenIds, uint256[] memory amounts) internal {
                  if (extension != address(0)) {
                      _checkMintPermissions(to, tokenIds, amounts);
                  }
                  if (to.length == 1 && tokenIds.length == 1 && amounts.length == 1) {
                       // Single mint
                      _mint(to[0], tokenIds[0], amounts[0], new bytes(0));            
                  } else if (to.length == 1 && tokenIds.length == amounts.length) {
                      // Batch mint to same receiver
                      _mintBatch(to[0], tokenIds, amounts, new bytes(0));
                  } else if (tokenIds.length == 1 && amounts.length == 1) {
                      // Mint of the same token/token amounts to various receivers
                      for (uint i; i < to.length;) {
                          _mint(to[i], tokenIds[0], amounts[0], new bytes(0));
                          unchecked { ++i; }
                      }
                  } else if (tokenIds.length == 1 && to.length == amounts.length) {
                      // Mint of the same token with different amounts to different receivers
                      for (uint i; i < to.length;) {
                          _mint(to[i], tokenIds[0], amounts[i], new bytes(0));
                          unchecked { ++i; }
                      }
                  } else if (to.length == tokenIds.length && to.length == amounts.length) {
                      // Mint of different tokens and different amounts to different receivers
                      for (uint i; i < to.length;) {
                          _mint(to[i], tokenIds[i], amounts[i], new bytes(0));
                          unchecked { ++i; }
                      }
                  } else {
                      revert("Invalid input");
                  }
              }
              /**
               * @dev See {IERC1155CreatorCore-tokenExtension}.
               */
              function tokenExtension(uint256 tokenId) public view virtual override returns (address) {
                  return _tokenExtension(tokenId);
              }
              /**
               * @dev See {IERC1155CreatorCore-burn}.
               */
              function burn(address account, uint256[] memory tokenIds, uint256[] memory amounts) public virtual override nonReentrant {
                  require(account == msg.sender || isApprovedForAll(account, msg.sender), "Caller is not owner nor approved");
                  require(tokenIds.length == amounts.length, "Invalid input");
                  if (tokenIds.length == 1) {
                      _burn(account, tokenIds[0], amounts[0]);
                  } else {
                      _burnBatch(account, tokenIds, amounts);
                  }
                  _postBurn(account, tokenIds, amounts);
              }
              /**
               * @dev See {ICreatorCore-setRoyalties}.
               */
              function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                  _setRoyaltiesExtension(address(0), receivers, basisPoints);
              }
              /**
               * @dev See {ICreatorCore-setRoyalties}.
               */
              function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                  _setRoyalties(tokenId, receivers, basisPoints);
              }
              /**
               * @dev See {ICreatorCore-setRoyaltiesExtension}.
               */
              function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external override adminRequired {
                  _setRoyaltiesExtension(extension, receivers, basisPoints);
              }
              /**
               * @dev See {ICreatorCore-getRoyalties}.
               */
              function getRoyalties(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) {
                  return _getRoyalties(tokenId);
              }
              /**
               * @dev See {ICreatorCore-getFees}.
               */
              function getFees(uint256 tokenId) external view virtual override returns (address payable[] memory, uint256[] memory) {
                  return _getRoyalties(tokenId);
              }
              /**
               * @dev See {ICreatorCore-getFeeRecipients}.
               */
              function getFeeRecipients(uint256 tokenId) external view virtual override returns (address payable[] memory) {
                  return _getRoyaltyReceivers(tokenId);
              }
              /**
               * @dev See {ICreatorCore-getFeeBps}.
               */
              function getFeeBps(uint256 tokenId) external view virtual override returns (uint[] memory) {
                  return _getRoyaltyBPS(tokenId);
              }
              
              /**
               * @dev See {ICreatorCore-royaltyInfo}.
               */
              function royaltyInfo(uint256 tokenId, uint256 value) external view virtual override returns (address, uint256) {
                  return _getRoyaltyInfo(tokenId, value);
              } 
              /**
               * @dev See {IERC1155-uri}.
               */
              function uri(uint256 tokenId) public view virtual override returns (string memory) {
                  return _tokenURI(tokenId);
              }
              
              /**
               * @dev Total amount of tokens in with a given id.
               */
              function totalSupply(uint256 tokenId) external view virtual override returns (uint256) {
                  return _totalSupply[tokenId];
              }
              /**
               * @dev See {ERC1155-_mint}.
               */
              function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual override {
                  super._mint(account, id, amount, data);
                  _totalSupply[id] += amount;
              }
              /**
               * @dev See {ERC1155-_mintBatch}.
               */
              function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override {
                  super._mintBatch(to, ids, amounts, data);
                  for (uint i; i < ids.length;) {
                      _totalSupply[ids[i]] += amounts[i];
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev See {ERC1155-_burn}.
               */
              function _burn(address account, uint256 id, uint256 amount) internal virtual override {
                  super._burn(account, id, amount);
                  _totalSupply[id] -= amount;
              }
              /**
               * @dev See {ERC1155-_burnBatch}.
               */
              function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual override {
                  super._burnBatch(account, ids, amounts);
                  for (uint i; i < ids.length;) {
                      _totalSupply[ids[i]] -= amounts[i];
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev See {ICreatorCore-setApproveTransfer}.
               */
              function setApproveTransfer(address extension) external override adminRequired {
                  _setApproveTransferBase(extension);
              }
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
          import "@openzeppelin/contracts/utils/Strings.sol";
          import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
          import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
          import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
          import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
          import "../extensions/ICreatorExtensionTokenURI.sol";
          import "../extensions/ICreatorExtensionRoyalties.sol";
          import "./ICreatorCore.sol";
          /**
           * @dev Core creator implementation
           */
          abstract contract CreatorCore is ReentrancyGuard, ICreatorCore, ERC165 {
              using Strings for uint256;
              using EnumerableSet for EnumerableSet.AddressSet;
              using AddressUpgradeable for address;
              uint256 internal _tokenCount = 0;
              // Base approve transfers address location
              address internal _approveTransferBase;
              // Track registered extensions data
              EnumerableSet.AddressSet internal _extensions;
              EnumerableSet.AddressSet internal _blacklistedExtensions;
              mapping (address => address) internal _extensionPermissions;
              mapping (address => bool) internal _extensionApproveTransfers;
              
              // For tracking which extension a token was minted by
              mapping (uint256 => address) internal _tokensExtension;
              // The baseURI for a given extension
              mapping (address => string) private _extensionBaseURI;
              mapping (address => bool) private _extensionBaseURIIdentical;
              // The prefix for any tokens with a uri configured
              mapping (address => string) private _extensionURIPrefix;
              // Mapping for individual token URIs
              mapping (uint256 => string) internal _tokenURIs;
              // Royalty configurations
              struct RoyaltyConfig {
                  address payable receiver;
                  uint16 bps;
              }
              mapping (address => RoyaltyConfig[]) internal _extensionRoyalty;
              mapping (uint256 => RoyaltyConfig[]) internal _tokenRoyalty;
              bytes4 private constant _CREATOR_CORE_V1 = 0x28f10a21;
              /**
               * External interface identifiers for royalties
               */
              /**
               *  @dev CreatorCore
               *
               *  bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6
               *
               *  => 0xbb3bafd6 = 0xbb3bafd6
               */
              bytes4 private constant _INTERFACE_ID_ROYALTIES_CREATORCORE = 0xbb3bafd6;
              /**
               *  @dev Rarible: RoyaltiesV1
               *
               *  bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
               *  bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
               *
               *  => 0xb9c4d9fb ^ 0x0ebd4c7f = 0xb7799584
               */
              bytes4 private constant _INTERFACE_ID_ROYALTIES_RARIBLE = 0xb7799584;
              /**
               *  @dev Foundation
               *
               *  bytes4(keccak256('getFees(uint256)')) == 0xd5a06d4c
               *
               *  => 0xd5a06d4c = 0xd5a06d4c
               */
              bytes4 private constant _INTERFACE_ID_ROYALTIES_FOUNDATION = 0xd5a06d4c;
              /**
               *  @dev EIP-2981
               *
               * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
               *
               * => 0x2a55205a = 0x2a55205a
               */
              bytes4 private constant _INTERFACE_ID_ROYALTIES_EIP2981 = 0x2a55205a;
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(ICreatorCore).interfaceId || interfaceId == _CREATOR_CORE_V1 || super.supportsInterface(interfaceId)
                      || interfaceId == _INTERFACE_ID_ROYALTIES_CREATORCORE || interfaceId == _INTERFACE_ID_ROYALTIES_RARIBLE
                      || interfaceId == _INTERFACE_ID_ROYALTIES_FOUNDATION || interfaceId == _INTERFACE_ID_ROYALTIES_EIP2981;
              }
              /**
               * @dev Only allows registered extensions to call the specified function
               */
              function requireExtension() internal view {
                  require(_extensions.contains(msg.sender), "Must be registered extension");
              }
              /**
               * @dev Only allows non-blacklisted extensions
               */
              function requireNonBlacklist(address extension) internal view {
                  require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
              }   
              /**
               * @dev See {ICreatorCore-getExtensions}.
               */
              function getExtensions() external view override returns (address[] memory extensions) {
                  extensions = new address[](_extensions.length());
                  for (uint i; i < _extensions.length();) {
                      extensions[i] = _extensions.at(i);
                      unchecked { ++i; }
                  }
                  return extensions;
              }
              /**
               * @dev Register an extension
               */
              function _registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) internal {
                  require(extension != address(this) && extension.isContract(), "Invalid");
                  emit ExtensionRegistered(extension, msg.sender);
                  _extensionBaseURI[extension] = baseURI;
                  _extensionBaseURIIdentical[extension] = baseURIIdentical;
                  _extensions.add(extension);
                  _setApproveTransferExtension(extension, true);
              }
              /**
               * @dev See {ICreatorCore-setApproveTransferExtension}.
               */
              function setApproveTransferExtension(bool enabled) external override {
                  requireExtension();
                  _setApproveTransferExtension(msg.sender, enabled);
              }
              /**
               * @dev Set whether or not tokens minted by the extension defers transfer approvals to the extension
               */
              function _setApproveTransferExtension(address extension, bool enabled) internal virtual;
              /**
               * @dev Unregister an extension
               */
              function _unregisterExtension(address extension) internal {
                  emit ExtensionUnregistered(extension, msg.sender);
                  _extensions.remove(extension);
              }
              /**
               * @dev Blacklist an extension
               */
              function _blacklistExtension(address extension) internal {
                 require(extension != address(0) && extension != address(this), "Cannot blacklist yourself");
                 if (_extensions.contains(extension)) {
                     emit ExtensionUnregistered(extension, msg.sender);
                     _extensions.remove(extension);
                 }
                 if (!_blacklistedExtensions.contains(extension)) {
                     emit ExtensionBlacklisted(extension, msg.sender);
                     _blacklistedExtensions.add(extension);
                 }
              }
              /**
               * @dev Set base token uri for an extension
               */
              function _setBaseTokenURIExtension(string calldata uri, bool identical) internal {
                  _extensionBaseURI[msg.sender] = uri;
                  _extensionBaseURIIdentical[msg.sender] = identical;
              }
              /**
               * @dev Set token uri prefix for an extension
               */
              function _setTokenURIPrefixExtension(string calldata prefix) internal {
                  _extensionURIPrefix[msg.sender] = prefix;
              }
              /**
               * @dev Set token uri for a token of an extension
               */
              function _setTokenURIExtension(uint256 tokenId, string calldata uri) internal {
                  require(_tokensExtension[tokenId] == msg.sender, "Invalid token");
                  _tokenURIs[tokenId] = uri;
              }
              /**
               * @dev Set base token uri for tokens with no extension
               */
              function _setBaseTokenURI(string memory uri) internal {
                  _extensionBaseURI[address(0)] = uri;
              }
              /**
               * @dev Set token uri prefix for tokens with no extension
               */
              function _setTokenURIPrefix(string calldata prefix) internal {
                  _extensionURIPrefix[address(0)] = prefix;
              }
              /**
               * @dev Set token uri for a token with no extension
               */
              function _setTokenURI(uint256 tokenId, string calldata uri) internal {
                  require(tokenId > 0 && tokenId <= _tokenCount && _tokensExtension[tokenId] == address(0), "Invalid token");
                  _tokenURIs[tokenId] = uri;
              }
              /**
               * @dev Retrieve a token's URI
               */
              function _tokenURI(uint256 tokenId) internal view returns (string memory) {
                  require(tokenId > 0 && tokenId <= _tokenCount, "Invalid token");
                  address extension = _tokensExtension[tokenId];
                  require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
                  if (bytes(_tokenURIs[tokenId]).length != 0) {
                      if (bytes(_extensionURIPrefix[extension]).length != 0) {
                          return string(abi.encodePacked(_extensionURIPrefix[extension],_tokenURIs[tokenId]));
                      }
                      return _tokenURIs[tokenId];
                  }
                  if (ERC165Checker.supportsInterface(extension, type(ICreatorExtensionTokenURI).interfaceId)) {
                      return ICreatorExtensionTokenURI(extension).tokenURI(address(this), tokenId);
                  }
                  if (!_extensionBaseURIIdentical[extension]) {
                      return string(abi.encodePacked(_extensionBaseURI[extension], tokenId.toString()));
                  } else {
                      return _extensionBaseURI[extension];
                  }
              }
              /**
               * Get token extension
               */
              function _tokenExtension(uint256 tokenId) internal view returns (address extension) {
                  extension = _tokensExtension[tokenId];
                  require(extension != address(0), "No extension for token");
                  require(!_blacklistedExtensions.contains(extension), "Extension blacklisted");
                  return extension;
              }
              /**
               * Helper to get royalties for a token
               */
              function _getRoyalties(uint256 tokenId) view internal returns (address payable[] memory receivers, uint256[] memory bps) {
                  // Get token level royalties
                  RoyaltyConfig[] memory royalties = _tokenRoyalty[tokenId];
                  if (royalties.length == 0) {
                      // Get extension specific royalties
                      address extension = _tokensExtension[tokenId];
                      if (extension != address(0)) {
                          if (ERC165Checker.supportsInterface(extension, type(ICreatorExtensionRoyalties).interfaceId)) {
                              (receivers, bps) = ICreatorExtensionRoyalties(extension).getRoyalties(address(this), tokenId);
                              // Extension override exists, just return that
                              if (receivers.length > 0) return (receivers, bps);
                          }
                          royalties = _extensionRoyalty[extension];
                      }
                  }
                  if (royalties.length == 0) {
                      // Get the default royalty
                      royalties = _extensionRoyalty[address(0)];
                  }
                  
                  if (royalties.length > 0) {
                      receivers = new address payable[](royalties.length);
                      bps = new uint256[](royalties.length);
                      for (uint i; i < royalties.length;) {
                          receivers[i] = royalties[i].receiver;
                          bps[i] = royalties[i].bps;
                          unchecked { ++i; }
                      }
                  }
              }
              /**
               * Helper to get royalty receivers for a token
               */
              function _getRoyaltyReceivers(uint256 tokenId) view internal returns (address payable[] memory recievers) {
                  (recievers, ) = _getRoyalties(tokenId);
              }
              /**
               * Helper to get royalty basis points for a token
               */
              function _getRoyaltyBPS(uint256 tokenId) view internal returns (uint256[] memory bps) {
                  (, bps) = _getRoyalties(tokenId);
              }
              function _getRoyaltyInfo(uint256 tokenId, uint256 value) view internal returns (address receiver, uint256 amount){
                  (address payable[] memory receivers, uint256[] memory bps) = _getRoyalties(tokenId);
                  require(receivers.length <= 1, "More than 1 royalty receiver");
                  
                  if (receivers.length == 0) {
                      return (address(this), 0);
                  }
                  return (receivers[0], bps[0]*value/10000);
              }
              /**
               * Set royalties for a token
               */
              function _setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) internal {
                 _checkRoyalties(receivers, basisPoints);
                  delete _tokenRoyalty[tokenId];
                  _setRoyalties(receivers, basisPoints, _tokenRoyalty[tokenId]);
                  emit RoyaltiesUpdated(tokenId, receivers, basisPoints);
              }
              /**
               * Set royalties for all tokens of an extension
               */
              function _setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) internal {
                  _checkRoyalties(receivers, basisPoints);
                  delete _extensionRoyalty[extension];
                  _setRoyalties(receivers, basisPoints, _extensionRoyalty[extension]);
                  if (extension == address(0)) {
                      emit DefaultRoyaltiesUpdated(receivers, basisPoints);
                  } else {
                      emit ExtensionRoyaltiesUpdated(extension, receivers, basisPoints);
                  }
              }
              /**
               * Helper function to check that royalties provided are valid
               */
              function _checkRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) private pure {
                  require(receivers.length == basisPoints.length, "Invalid input");
                  uint256 totalBasisPoints;
                  for (uint i; i < basisPoints.length;) {
                      totalBasisPoints += basisPoints[i];
                      unchecked { ++i; }
                  }
                  require(totalBasisPoints < 10000, "Invalid total royalties");
              }
              /**
               * Helper function to set royalties
               */
              function _setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints, RoyaltyConfig[] storage royalties) private {
                  for (uint i; i < basisPoints.length;) {
                      royalties.push(
                          RoyaltyConfig(
                              {
                                  receiver: receivers[i],
                                  bps: uint16(basisPoints[i])
                              }
                          )
                      );
                      unchecked { ++i; }
                  }
              }
              /**
               * @dev See {ICreatorCore-getApproveTransfer}.
               */
              function getApproveTransfer() external view override returns (address) {
                  return _approveTransferBase;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
          import "../extensions/ERC1155/IERC1155CreatorExtensionApproveTransfer.sol";
          import "../extensions/ERC1155/IERC1155CreatorExtensionBurnable.sol";
          import "../permissions/ERC1155/IERC1155CreatorMintPermissions.sol";
          import "./IERC1155CreatorCore.sol";
          import "./CreatorCore.sol";
          /**
           * @dev Core ERC1155 creator implementation
           */
          abstract contract ERC1155CreatorCore is CreatorCore, IERC1155CreatorCore {
              uint256 constant public VERSION = 2;
              using EnumerableSet for EnumerableSet.AddressSet;
              string public name;
              string public symbol;
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(CreatorCore, IERC165) returns (bool) {
                  return interfaceId == type(IERC1155CreatorCore).interfaceId || super.supportsInterface(interfaceId);
              }
              /**
               * @dev See {CreatorCore-_setApproveTransferExtension}
               */
              function _setApproveTransferExtension(address extension, bool enabled) internal override {
                  if (ERC165Checker.supportsInterface(extension, type(IERC1155CreatorExtensionApproveTransfer).interfaceId)) {
                      _extensionApproveTransfers[extension] = enabled;
                      emit ExtensionApproveTransferUpdated(extension, enabled);
                  }
              }
              /**
               * @dev Set the base contract's approve transfer contract location
               */
              function _setApproveTransferBase(address extension) internal {
                  _approveTransferBase = extension;
                  emit ApproveTransferUpdated(extension);
              }
              /**
               * @dev Set mint permissions for an extension
               */
              function _setMintPermissions(address extension, address permissions) internal {
                  require(_extensions.contains(extension), "Invalid extension");
                  require(permissions == address(0) || ERC165Checker.supportsInterface(permissions, type(IERC1155CreatorMintPermissions).interfaceId), "Invalid address");
                  if (_extensionPermissions[extension] != permissions) {
                      _extensionPermissions[extension] = permissions;
                      emit MintPermissionsUpdated(extension, permissions, msg.sender);
                  }
              }
              /**
               * Check if an extension can mint
               */
              function _checkMintPermissions(address[] memory to, uint256[] memory tokenIds, uint256[] memory amounts) internal {
                  if (_extensionPermissions[msg.sender] != address(0)) {
                      IERC1155CreatorMintPermissions(_extensionPermissions[msg.sender]).approveMint(msg.sender, to, tokenIds, amounts);
                  }
              }
              /**
               * Post burn actions
               */
              function _postBurn(address owner, uint256[] memory tokenIds, uint256[] memory amounts) internal virtual {
                  require(tokenIds.length > 0, "Invalid input");
                  address extension = _tokensExtension[tokenIds[0]];
                  for (uint i; i < tokenIds.length;) {
                      require(_tokensExtension[tokenIds[i]] == extension, "Mismatched token originators");
                      unchecked { ++i; }
                  }
                  // Callback to originating extension if needed
                  if (extension != address(0)) {
                     if (ERC165Checker.supportsInterface(extension, type(IERC1155CreatorExtensionBurnable).interfaceId)) {
                         IERC1155CreatorExtensionBurnable(extension).onBurn(owner, tokenIds, amounts);
                     }
                  }
              }
              /**
               * Approve a transfer
               */
              function _approveTransfer(address from, address to, uint256[] memory tokenIds, uint256[] memory amounts) internal {
                  require(tokenIds.length > 0, "Invalid input");
                  address extension = _tokensExtension[tokenIds[0]];
                  for (uint i; i < tokenIds.length;) {
                      require(_tokensExtension[tokenIds[i]] == extension, "Mismatched token originators");
                      unchecked { ++i; }
                  }
                  if (_extensionApproveTransfers[extension]) {
                      require(IERC1155CreatorExtensionApproveTransfer(extension).approveTransfer(msg.sender, from, to, tokenIds, amounts), "Extension approval failure");
                  } else if (_approveTransferBase != address(0)) {
                      require(IERC1155CreatorExtensionApproveTransfer(_approveTransferBase).approveTransfer(msg.sender, from, to, tokenIds, amounts), "Extension approval failure");
                  }
              }
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Core creator interface
           */
          interface ICreatorCore is IERC165 {
              event ExtensionRegistered(address indexed extension, address indexed sender);
              event ExtensionUnregistered(address indexed extension, address indexed sender);
              event ExtensionBlacklisted(address indexed extension, address indexed sender);
              event MintPermissionsUpdated(address indexed extension, address indexed permissions, address indexed sender);
              event RoyaltiesUpdated(uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints);
              event DefaultRoyaltiesUpdated(address payable[] receivers, uint256[] basisPoints);
              event ApproveTransferUpdated(address extension);
              event ExtensionRoyaltiesUpdated(address indexed extension, address payable[] receivers, uint256[] basisPoints);
              event ExtensionApproveTransferUpdated(address indexed extension, bool enabled);
              /**
               * @dev gets address of all extensions
               */
              function getExtensions() external view returns (address[] memory);
              /**
               * @dev add an extension.  Can only be called by contract owner or admin.
               * extension address must point to a contract implementing ICreatorExtension.
               * Returns True if newly added, False if already added.
               */
              function registerExtension(address extension, string calldata baseURI) external;
              /**
               * @dev add an extension.  Can only be called by contract owner or admin.
               * extension address must point to a contract implementing ICreatorExtension.
               * Returns True if newly added, False if already added.
               */
              function registerExtension(address extension, string calldata baseURI, bool baseURIIdentical) external;
              /**
               * @dev add an extension.  Can only be called by contract owner or admin.
               * Returns True if removed, False if already removed.
               */
              function unregisterExtension(address extension) external;
              /**
               * @dev blacklist an extension.  Can only be called by contract owner or admin.
               * This function will destroy all ability to reference the metadata of any tokens created
               * by the specified extension. It will also unregister the extension if needed.
               * Returns True if removed, False if already removed.
               */
              function blacklistExtension(address extension) external;
              /**
               * @dev set the baseTokenURI of an extension.  Can only be called by extension.
               */
              function setBaseTokenURIExtension(string calldata uri) external;
              /**
               * @dev set the baseTokenURI of an extension.  Can only be called by extension.
               * For tokens with no uri configured, tokenURI will return "uri+tokenId"
               */
              function setBaseTokenURIExtension(string calldata uri, bool identical) external;
              /**
               * @dev set the common prefix of an extension.  Can only be called by extension.
               * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
               * Useful if you want to use ipfs/arweave
               */
              function setTokenURIPrefixExtension(string calldata prefix) external;
              /**
               * @dev set the tokenURI of a token extension.  Can only be called by extension that minted token.
               */
              function setTokenURIExtension(uint256 tokenId, string calldata uri) external;
              /**
               * @dev set the tokenURI of a token extension for multiple tokens.  Can only be called by extension that minted token.
               */
              function setTokenURIExtension(uint256[] memory tokenId, string[] calldata uri) external;
              /**
               * @dev set the baseTokenURI for tokens with no extension.  Can only be called by owner/admin.
               * For tokens with no uri configured, tokenURI will return "uri+tokenId"
               */
              function setBaseTokenURI(string calldata uri) external;
              /**
               * @dev set the common prefix for tokens with no extension.  Can only be called by owner/admin.
               * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI"
               * Useful if you want to use ipfs/arweave
               */
              function setTokenURIPrefix(string calldata prefix) external;
              /**
               * @dev set the tokenURI of a token with no extension.  Can only be called by owner/admin.
               */
              function setTokenURI(uint256 tokenId, string calldata uri) external;
              /**
               * @dev set the tokenURI of multiple tokens with no extension.  Can only be called by owner/admin.
               */
              function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external;
              /**
               * @dev set a permissions contract for an extension.  Used to control minting.
               */
              function setMintPermissions(address extension, address permissions) external;
              /**
               * @dev Configure so transfers of tokens created by the caller (must be extension) gets approval
               * from the extension before transferring
               */
              function setApproveTransferExtension(bool enabled) external;
              /**
               * @dev get the extension of a given token
               */
              function tokenExtension(uint256 tokenId) external view returns (address);
              /**
               * @dev Set default royalties
               */
              function setRoyalties(address payable[] calldata receivers, uint256[] calldata basisPoints) external;
              /**
               * @dev Set royalties of a token
               */
              function setRoyalties(uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
              /**
               * @dev Set royalties of an extension
               */
              function setRoyaltiesExtension(address extension, address payable[] calldata receivers, uint256[] calldata basisPoints) external;
              /**
               * @dev Get royalites of a token.  Returns list of receivers and basisPoints
               */
              function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
              
              // Royalty support for various other standards
              function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory);
              function getFeeBps(uint256 tokenId) external view returns (uint[] memory);
              function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
              function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256);
              /**
               * @dev Set the default approve transfer contract location.
               */
              function setApproveTransfer(address extension) external; 
              /**
               * @dev Get the default approve transfer contract location.
               */
              function getApproveTransfer() external view returns (address);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "./CreatorCore.sol";
          /**
           * @dev Core ERC1155 creator interface
           */
          interface IERC1155CreatorCore is ICreatorCore {
              /**
               * @dev mint a token with no extension. Can only be called by an admin.
               *
               * @param to       - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients)
               * @param amounts  - Can be a single element array (all recipients get the same amount) or a multi-element array
               * @param uris     - If no elements, all tokens use the default uri.
               *                   If any element is an empty string, the corresponding token uses the default uri.
               *
               *
               * Requirements: If to is a multi-element array, then uris must be empty or single element array
               *               If to is a multi-element array, then amounts must be a single element array or a multi-element array of the same size
               *               If to is a single element array, uris must be empty or the same length as amounts
               *
               * Examples:
               *    mintBaseNew(['0x....1', '0x....2'], [1], [])
               *        Mints a single new token, and gives 1 each to '0x....1' and '0x....2'.  Token uses default uri.
               *    
               *    mintBaseNew(['0x....1', '0x....2'], [1, 2], [])
               *        Mints a single new token, and gives 1 to '0x....1' and 2 to '0x....2'.  Token uses default uri.
               *    
               *    mintBaseNew(['0x....1'], [1, 2], ["", "http://token2.com"])
               *        Mints two new tokens to '0x....1'. 1 of the first token, 2 of the second.  1st token uses default uri, second uses "http://token2.com".
               *    
               * @return Returns list of tokenIds minted
               */
              function mintBaseNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) external returns (uint256[] memory);
              /**
               * @dev batch mint existing token with no extension. Can only be called by an admin.
               *
               * @param to        - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients)
               * @param tokenIds  - Can be a single element array (all recipients get the same token) or a multi-element array
               * @param amounts   - Can be a single element array (all recipients get the same amount) or a multi-element array
               *
               * Requirements: If any of the parameters are multi-element arrays, they need to be the same length as other multi-element arrays
               *
               * Examples:
               *    mintBaseExisting(['0x....1', '0x....2'], [1], [10])
               *        Mints 10 of tokenId 1 to each of '0x....1' and '0x....2'.
               *    
               *    mintBaseExisting(['0x....1', '0x....2'], [1, 2], [10, 20])
               *        Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 2 to '0x....2'.
               *    
               *    mintBaseExisting(['0x....1'], [1, 2], [10, 20])
               *        Mints 10 of tokenId 1 and 20 of tokenId 2 to '0x....1'.
               *    
               *    mintBaseExisting(['0x....1', '0x....2'], [1], [10, 20])
               *        Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 1 to '0x....2'.
               *    
               */
              function mintBaseExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
              /**
               * @dev mint a token from an extension. Can only be called by a registered extension.
               *
               * @param to       - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients)
               * @param amounts  - Can be a single element array (all recipients get the same amount) or a multi-element array
               * @param uris     - If no elements, all tokens use the default uri.
               *                   If any element is an empty string, the corresponding token uses the default uri.
               *
               *
               * Requirements: If to is a multi-element array, then uris must be empty or single element array
               *               If to is a multi-element array, then amounts must be a single element array or a multi-element array of the same size
               *               If to is a single element array, uris must be empty or the same length as amounts
               *
               * Examples:
               *    mintExtensionNew(['0x....1', '0x....2'], [1], [])
               *        Mints a single new token, and gives 1 each to '0x....1' and '0x....2'.  Token uses default uri.
               *    
               *    mintExtensionNew(['0x....1', '0x....2'], [1, 2], [])
               *        Mints a single new token, and gives 1 to '0x....1' and 2 to '0x....2'.  Token uses default uri.
               *    
               *    mintExtensionNew(['0x....1'], [1, 2], ["", "http://token2.com"])
               *        Mints two new tokens to '0x....1'. 1 of the first token, 2 of the second.  1st token uses default uri, second uses "http://token2.com".
               *    
               * @return Returns list of tokenIds minted
               */
              function mintExtensionNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) external returns (uint256[] memory);
              /**
               * @dev batch mint existing token from extension. Can only be called by a registered extension.
               *
               * @param to        - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients)
               * @param tokenIds  - Can be a single element array (all recipients get the same token) or a multi-element array
               * @param amounts   - Can be a single element array (all recipients get the same amount) or a multi-element array
               *
               * Requirements: If any of the parameters are multi-element arrays, they need to be the same length as other multi-element arrays
               *
               * Examples:
               *    mintExtensionExisting(['0x....1', '0x....2'], [1], [10])
               *        Mints 10 of tokenId 1 to each of '0x....1' and '0x....2'.
               *    
               *    mintExtensionExisting(['0x....1', '0x....2'], [1, 2], [10, 20])
               *        Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 2 to '0x....2'.
               *    
               *    mintExtensionExisting(['0x....1'], [1, 2], [10, 20])
               *        Mints 10 of tokenId 1 and 20 of tokenId 2 to '0x....1'.
               *    
               *    mintExtensionExisting(['0x....1', '0x....2'], [1], [10, 20])
               *        Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 1 to '0x....2'.
               *    
               */
              function mintExtensionExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
              /**
               * @dev burn tokens. Can only be called by token owner or approved address.
               * On burn, calls back to the registered extension's onBurn method
               */
              function burn(address account, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
              /**
               * @dev Total amount of tokens in with a given tokenId.
               */
              function totalSupply(uint256 tokenId) external view returns (uint256);
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * Implement this if you want your extension to approve a transfer
           */
          interface IERC1155CreatorExtensionApproveTransfer is IERC165 {
              /**
               * @dev Set whether or not the creator contract will check the extension for approval of token transfer
               */
              function setApproveTransfer(address creator, bool enabled) external;
              /**
               * @dev Called by creator contract to approve a transfer
               */
              function approveTransfer(address operator, address from, address to, uint256[] calldata tokenIds, uint256[] calldata amounts) external returns (bool);
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Your extension is required to implement this interface if it wishes
           * to receive the onBurn callback whenever a token the extension created is
           * burned
           */
          interface IERC1155CreatorExtensionBurnable is IERC165 {
              /**
               * @dev callback handler for burn events
               */
              function onBurn(address owner, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Implement this if you want your extension to have overloadable royalties
           */
          interface ICreatorExtensionRoyalties is IERC165 {
              /**
               * Get the royalties for a given creator/tokenId
               */
              function getRoyalties(address creator, uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Implement this if you want your extension to have overloadable URI's
           */
          interface ICreatorExtensionTokenURI is IERC165 {
              /**
               * Get the uri for a given creator/tokenId
               */
              function tokenURI(address creator, uint256 tokenId) external view returns (string memory);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Required interface of an ERC1155Creator compliant extension contracts.
           */
          interface IERC1155CreatorMintPermissions is IERC165 {
              /**
               * @dev get approval to mint
               */
              function approveMint(address extension, address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
          import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
          import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
          import "./IAdminControl.sol";
          abstract contract AdminControlUpgradeable is OwnableUpgradeable, IAdminControl, ERC165 {
              using EnumerableSet for EnumerableSet.AddressSet;
              // Track registered admins
              EnumerableSet.AddressSet private _admins;
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(IAdminControl).interfaceId
                      || super.supportsInterface(interfaceId);
              }
              /**
               * @dev Only allows approved admins to call the specified function
               */
              modifier adminRequired() {
                  require(owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin");
                  _;
              }   
              /**
               * @dev See {IAdminControl-getAdmins}.
               */
              function getAdmins() external view override returns (address[] memory admins) {
                  admins = new address[](_admins.length());
                  for (uint i = 0; i < _admins.length(); i++) {
                      admins[i] = _admins.at(i);
                  }
                  return admins;
              }
              /**
               * @dev See {IAdminControl-approveAdmin}.
               */
              function approveAdmin(address admin) external override onlyOwner {
                  if (!_admins.contains(admin)) {
                      emit AdminApproved(admin, msg.sender);
                      _admins.add(admin);
                  }
              }
              /**
               * @dev See {IAdminControl-revokeAdmin}.
               */
              function revokeAdmin(address admin) external override onlyOwner {
                  if (_admins.contains(admin)) {
                      emit AdminRevoked(admin, msg.sender);
                      _admins.remove(admin);
                  }
              }
              /**
               * @dev See {IAdminControl-isAdmin}.
               */
              function isAdmin(address admin) public override view returns (bool) {
                  return (owner() == admin || _admins.contains(admin));
              }
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Interface for admin control
           */
          interface IAdminControl is IERC165 {
              event AdminApproved(address indexed account, address indexed sender);
              event AdminRevoked(address indexed account, address indexed sender);
              /**
               * @dev gets address of all admins
               */
              function getAdmins() external view returns (address[] memory);
              /**
               * @dev add an admin.  Can only be called by contract owner.
               */
              function approveAdmin(address admin) external;
              /**
               * @dev remove an admin.  Can only be called by contract owner.
               */
              function revokeAdmin(address admin) external;
              /**
               * @dev checks whether or not given address is an admin
               * Returns True if they are
               */
              function isAdmin(address admin) external view returns (bool);
          }// SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
          pragma solidity ^0.8.0;
          import "../utils/ContextUpgradeable.sol";
          import "../proxy/utils/Initializable.sol";
          /**
           * @dev Contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * By default, the owner account will be the one that deploys the contract. This
           * can later be changed with {transferOwnership}.
           *
           * This module is used through inheritance. It will make available the modifier
           * `onlyOwner`, which can be applied to your functions to restrict their use to
           * the owner.
           */
          abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal onlyInitializing {
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal onlyInitializing {
                  _transferOwnership(_msgSender());
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  _checkOwner();
                  _;
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if the sender is not the owner.
               */
              function _checkOwner() internal view virtual {
                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
              }
              /**
               * @dev Leaves the contract without owner. It will not be possible to call
               * `onlyOwner` functions anymore. Can only be called by the current owner.
               *
               * NOTE: Renouncing ownership will leave the contract without an owner,
               * thereby removing any functionality that is only available to the owner.
               */
              function renounceOwnership() public virtual onlyOwner {
                  _transferOwnership(address(0));
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Can only be called by the current owner.
               */
              function transferOwnership(address newOwner) public virtual onlyOwner {
                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
          pragma solidity ^0.8.2;
          import "../../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
           * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
           * case an upgrade adds a module that needs to be initialized.
           *
           * For example:
           *
           * [.hljs-theme-light.nopadding]
           * ```
           * contract MyToken is ERC20Upgradeable {
           *     function initialize() initializer public {
           *         __ERC20_init("MyToken", "MTK");
           *     }
           * }
           * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
           *     function initializeV2() reinitializer(2) public {
           *         __ERC20Permit_init("MyToken");
           *     }
           * }
           * ```
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           *
           * [CAUTION]
           * ====
           * Avoid leaving a contract uninitialized.
           *
           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
           * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
           * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
           *
           * [.hljs-theme-light.nopadding]
           * ```
           * /// @custom:oz-upgrades-unsafe-allow constructor
           * constructor() {
           *     _disableInitializers();
           * }
           * ```
           * ====
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               * @custom:oz-retyped-from bool
               */
              uint8 private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Triggered when the contract has been initialized or reinitialized.
               */
              event Initialized(uint8 version);
              /**
               * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
               * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
               */
              modifier initializer() {
                  bool isTopLevelCall = !_initializing;
                  require(
                      (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                      "Initializable: contract is already initialized"
                  );
                  _initialized = 1;
                  if (isTopLevelCall) {
                      _initializing = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                      emit Initialized(1);
                  }
              }
              /**
               * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
               * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
               * used to initialize parent contracts.
               *
               * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
               * initialization step. This is essential to configure modules that are added through upgrades and that require
               * initialization.
               *
               * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
               * a contract, executing them in the right order is up to the developer or operator.
               */
              modifier reinitializer(uint8 version) {
                  require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                  _initialized = version;
                  _initializing = true;
                  _;
                  _initializing = false;
                  emit Initialized(version);
              }
              /**
               * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
               * {initializer} and {reinitializer} modifiers, directly or indirectly.
               */
              modifier onlyInitializing() {
                  require(_initializing, "Initializable: contract is not initializing");
                  _;
              }
              /**
               * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
               * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
               * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
               * through proxies.
               */
              function _disableInitializers() internal virtual {
                  require(!_initializing, "Initializable: contract is initializing");
                  if (_initialized < type(uint8).max) {
                      _initialized = type(uint8).max;
                      emit Initialized(type(uint8).max);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)
          pragma solidity ^0.8.0;
          import "./IERC1155Upgradeable.sol";
          import "./IERC1155ReceiverUpgradeable.sol";
          import "./extensions/IERC1155MetadataURIUpgradeable.sol";
          import "../../utils/AddressUpgradeable.sol";
          import "../../utils/ContextUpgradeable.sol";
          import "../../utils/introspection/ERC165Upgradeable.sol";
          import "../../proxy/utils/Initializable.sol";
          /**
           * @dev Implementation of the basic standard multi-token.
           * See https://eips.ethereum.org/EIPS/eip-1155
           * Originally based on code by Enjin: https://github.com/enjin/erc-1155
           *
           * _Available since v3.1._
           */
          contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155Upgradeable, IERC1155MetadataURIUpgradeable {
              using AddressUpgradeable for address;
              // Mapping from token ID to account balances
              mapping(uint256 => mapping(address => uint256)) private _balances;
              // Mapping from account to operator approvals
              mapping(address => mapping(address => bool)) private _operatorApprovals;
              // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
              string private _uri;
              /**
               * @dev See {_setURI}.
               */
              function __ERC1155_init(string memory uri_) internal onlyInitializing {
                  __ERC1155_init_unchained(uri_);
              }
              function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
                  _setURI(uri_);
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {
                  return
                      interfaceId == type(IERC1155Upgradeable).interfaceId ||
                      interfaceId == type(IERC1155MetadataURIUpgradeable).interfaceId ||
                      super.supportsInterface(interfaceId);
              }
              /**
               * @dev See {IERC1155MetadataURI-uri}.
               *
               * This implementation returns the same URI for *all* token types. It relies
               * on the token type ID substitution mechanism
               * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
               *
               * Clients calling this function must replace the `\\{id\\}` substring with the
               * actual token type ID.
               */
              function uri(uint256) public view virtual override returns (string memory) {
                  return _uri;
              }
              /**
               * @dev See {IERC1155-balanceOf}.
               *
               * Requirements:
               *
               * - `account` cannot be the zero address.
               */
              function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
                  require(account != address(0), "ERC1155: address zero is not a valid owner");
                  return _balances[id][account];
              }
              /**
               * @dev See {IERC1155-balanceOfBatch}.
               *
               * Requirements:
               *
               * - `accounts` and `ids` must have the same length.
               */
              function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
                  public
                  view
                  virtual
                  override
                  returns (uint256[] memory)
              {
                  require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
                  uint256[] memory batchBalances = new uint256[](accounts.length);
                  for (uint256 i = 0; i < accounts.length; ++i) {
                      batchBalances[i] = balanceOf(accounts[i], ids[i]);
                  }
                  return batchBalances;
              }
              /**
               * @dev See {IERC1155-setApprovalForAll}.
               */
              function setApprovalForAll(address operator, bool approved) public virtual override {
                  _setApprovalForAll(_msgSender(), operator, approved);
              }
              /**
               * @dev See {IERC1155-isApprovedForAll}.
               */
              function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
                  return _operatorApprovals[account][operator];
              }
              /**
               * @dev See {IERC1155-safeTransferFrom}.
               */
              function safeTransferFrom(
                  address from,
                  address to,
                  uint256 id,
                  uint256 amount,
                  bytes memory data
              ) public virtual override {
                  require(
                      from == _msgSender() || isApprovedForAll(from, _msgSender()),
                      "ERC1155: caller is not token owner nor approved"
                  );
                  _safeTransferFrom(from, to, id, amount, data);
              }
              /**
               * @dev See {IERC1155-safeBatchTransferFrom}.
               */
              function safeBatchTransferFrom(
                  address from,
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) public virtual override {
                  require(
                      from == _msgSender() || isApprovedForAll(from, _msgSender()),
                      "ERC1155: caller is not token owner nor approved"
                  );
                  _safeBatchTransferFrom(from, to, ids, amounts, data);
              }
              /**
               * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - `from` must have a balance of tokens of type `id` of at least `amount`.
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
               * acceptance magic value.
               */
              function _safeTransferFrom(
                  address from,
                  address to,
                  uint256 id,
                  uint256 amount,
                  bytes memory data
              ) internal virtual {
                  require(to != address(0), "ERC1155: transfer to the zero address");
                  address operator = _msgSender();
                  uint256[] memory ids = _asSingletonArray(id);
                  uint256[] memory amounts = _asSingletonArray(amount);
                  _beforeTokenTransfer(operator, from, to, ids, amounts, data);
                  uint256 fromBalance = _balances[id][from];
                  require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
                  unchecked {
                      _balances[id][from] = fromBalance - amount;
                  }
                  _balances[id][to] += amount;
                  emit TransferSingle(operator, from, to, id, amount);
                  _afterTokenTransfer(operator, from, to, ids, amounts, data);
                  _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
              }
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
               *
               * Emits a {TransferBatch} event.
               *
               * Requirements:
               *
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
               * acceptance magic value.
               */
              function _safeBatchTransferFrom(
                  address from,
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) internal virtual {
                  require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
                  require(to != address(0), "ERC1155: transfer to the zero address");
                  address operator = _msgSender();
                  _beforeTokenTransfer(operator, from, to, ids, amounts, data);
                  for (uint256 i = 0; i < ids.length; ++i) {
                      uint256 id = ids[i];
                      uint256 amount = amounts[i];
                      uint256 fromBalance = _balances[id][from];
                      require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
                      unchecked {
                          _balances[id][from] = fromBalance - amount;
                      }
                      _balances[id][to] += amount;
                  }
                  emit TransferBatch(operator, from, to, ids, amounts);
                  _afterTokenTransfer(operator, from, to, ids, amounts, data);
                  _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
              }
              /**
               * @dev Sets a new URI for all token types, by relying on the token type ID
               * substitution mechanism
               * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
               *
               * By this mechanism, any occurrence of the `\\{id\\}` substring in either the
               * URI or any of the amounts in the JSON file at said URI will be replaced by
               * clients with the token type ID.
               *
               * For example, the `https://token-cdn-domain/\\{id\\}.json` URI would be
               * interpreted by clients as
               * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
               * for token type ID 0x4cce0.
               *
               * See {uri}.
               *
               * Because these URIs cannot be meaningfully represented by the {URI} event,
               * this function emits no events.
               */
              function _setURI(string memory newuri) internal virtual {
                  _uri = newuri;
              }
              /**
               * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
               * acceptance magic value.
               */
              function _mint(
                  address to,
                  uint256 id,
                  uint256 amount,
                  bytes memory data
              ) internal virtual {
                  require(to != address(0), "ERC1155: mint to the zero address");
                  address operator = _msgSender();
                  uint256[] memory ids = _asSingletonArray(id);
                  uint256[] memory amounts = _asSingletonArray(amount);
                  _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
                  _balances[id][to] += amount;
                  emit TransferSingle(operator, address(0), to, id, amount);
                  _afterTokenTransfer(operator, address(0), to, ids, amounts, data);
                  _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
              }
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
               *
               * Emits a {TransferBatch} event.
               *
               * Requirements:
               *
               * - `ids` and `amounts` must have the same length.
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
               * acceptance magic value.
               */
              function _mintBatch(
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) internal virtual {
                  require(to != address(0), "ERC1155: mint to the zero address");
                  require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
                  address operator = _msgSender();
                  _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
                  for (uint256 i = 0; i < ids.length; i++) {
                      _balances[ids[i]][to] += amounts[i];
                  }
                  emit TransferBatch(operator, address(0), to, ids, amounts);
                  _afterTokenTransfer(operator, address(0), to, ids, amounts, data);
                  _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
              }
              /**
               * @dev Destroys `amount` tokens of token type `id` from `from`
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `from` must have at least `amount` tokens of token type `id`.
               */
              function _burn(
                  address from,
                  uint256 id,
                  uint256 amount
              ) internal virtual {
                  require(from != address(0), "ERC1155: burn from the zero address");
                  address operator = _msgSender();
                  uint256[] memory ids = _asSingletonArray(id);
                  uint256[] memory amounts = _asSingletonArray(amount);
                  _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
                  uint256 fromBalance = _balances[id][from];
                  require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
                  unchecked {
                      _balances[id][from] = fromBalance - amount;
                  }
                  emit TransferSingle(operator, from, address(0), id, amount);
                  _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
              }
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
               *
               * Emits a {TransferBatch} event.
               *
               * Requirements:
               *
               * - `ids` and `amounts` must have the same length.
               */
              function _burnBatch(
                  address from,
                  uint256[] memory ids,
                  uint256[] memory amounts
              ) internal virtual {
                  require(from != address(0), "ERC1155: burn from the zero address");
                  require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
                  address operator = _msgSender();
                  _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
                  for (uint256 i = 0; i < ids.length; i++) {
                      uint256 id = ids[i];
                      uint256 amount = amounts[i];
                      uint256 fromBalance = _balances[id][from];
                      require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
                      unchecked {
                          _balances[id][from] = fromBalance - amount;
                      }
                  }
                  emit TransferBatch(operator, from, address(0), ids, amounts);
                  _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
              }
              /**
               * @dev Approve `operator` to operate on all of `owner` tokens
               *
               * Emits an {ApprovalForAll} event.
               */
              function _setApprovalForAll(
                  address owner,
                  address operator,
                  bool approved
              ) internal virtual {
                  require(owner != operator, "ERC1155: setting approval status for self");
                  _operatorApprovals[owner][operator] = approved;
                  emit ApprovalForAll(owner, operator, approved);
              }
              /**
               * @dev Hook that is called before any token transfer. This includes minting
               * and burning, as well as batched variants.
               *
               * The same hook is called on both single and batched variants. For single
               * transfers, the length of the `ids` and `amounts` arrays will be 1.
               *
               * Calling conditions (for each `id` and `amount` pair):
               *
               * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
               * of token type `id` will be  transferred to `to`.
               * - When `from` is zero, `amount` tokens of token type `id` will be minted
               * for `to`.
               * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
               * will be burned.
               * - `from` and `to` are never both zero.
               * - `ids` and `amounts` have the same, non-zero length.
               *
               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
               */
              function _beforeTokenTransfer(
                  address operator,
                  address from,
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) internal virtual {}
              /**
               * @dev Hook that is called after any token transfer. This includes minting
               * and burning, as well as batched variants.
               *
               * The same hook is called on both single and batched variants. For single
               * transfers, the length of the `id` and `amount` arrays will be 1.
               *
               * Calling conditions (for each `id` and `amount` pair):
               *
               * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
               * of token type `id` will be  transferred to `to`.
               * - When `from` is zero, `amount` tokens of token type `id` will be minted
               * for `to`.
               * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
               * will be burned.
               * - `from` and `to` are never both zero.
               * - `ids` and `amounts` have the same, non-zero length.
               *
               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
               */
              function _afterTokenTransfer(
                  address operator,
                  address from,
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) internal virtual {}
              function _doSafeTransferAcceptanceCheck(
                  address operator,
                  address from,
                  address to,
                  uint256 id,
                  uint256 amount,
                  bytes memory data
              ) private {
                  if (to.isContract()) {
                      try IERC1155ReceiverUpgradeable(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                          if (response != IERC1155ReceiverUpgradeable.onERC1155Received.selector) {
                              revert("ERC1155: ERC1155Receiver rejected tokens");
                          }
                      } catch Error(string memory reason) {
                          revert(reason);
                      } catch {
                          revert("ERC1155: transfer to non ERC1155Receiver implementer");
                      }
                  }
              }
              function _doSafeBatchTransferAcceptanceCheck(
                  address operator,
                  address from,
                  address to,
                  uint256[] memory ids,
                  uint256[] memory amounts,
                  bytes memory data
              ) private {
                  if (to.isContract()) {
                      try IERC1155ReceiverUpgradeable(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                          bytes4 response
                      ) {
                          if (response != IERC1155ReceiverUpgradeable.onERC1155BatchReceived.selector) {
                              revert("ERC1155: ERC1155Receiver rejected tokens");
                          }
                      } catch Error(string memory reason) {
                          revert(reason);
                      } catch {
                          revert("ERC1155: transfer to non ERC1155Receiver implementer");
                      }
                  }
              }
              function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
                  uint256[] memory array = new uint256[](1);
                  array[0] = element;
                  return array;
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[47] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
          pragma solidity ^0.8.0;
          import "../IERC1155Upgradeable.sol";
          /**
           * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
           * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
           *
           * _Available since v3.1._
           */
          interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable {
              /**
               * @dev Returns the URI for token type `id`.
               *
               * If the `\\{id\\}` substring is present in the URI, it must be replaced by
               * clients with the actual token type ID.
               */
              function uri(uint256 id) external view returns (string memory);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165Upgradeable.sol";
          /**
           * @dev _Available since v3.1._
           */
          interface IERC1155ReceiverUpgradeable is IERC165Upgradeable {
              /**
               * @dev Handles the receipt of a single ERC1155 token type. This function is
               * called at the end of a `safeTransferFrom` after the balance has been updated.
               *
               * NOTE: To accept the transfer, this must return
               * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
               * (i.e. 0xf23a6e61, or its own function selector).
               *
               * @param operator The address which initiated the transfer (i.e. msg.sender)
               * @param from The address which previously owned the token
               * @param id The ID of the token being transferred
               * @param value The amount of tokens being transferred
               * @param data Additional data with no specified format
               * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
               */
              function onERC1155Received(
                  address operator,
                  address from,
                  uint256 id,
                  uint256 value,
                  bytes calldata data
              ) external returns (bytes4);
              /**
               * @dev Handles the receipt of a multiple ERC1155 token types. This function
               * is called at the end of a `safeBatchTransferFrom` after the balances have
               * been updated.
               *
               * NOTE: To accept the transfer(s), this must return
               * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
               * (i.e. 0xbc197c81, or its own function selector).
               *
               * @param operator The address which initiated the batch transfer (i.e. msg.sender)
               * @param from The address which previously owned the token
               * @param ids An array containing ids of each token being transferred (order and length must match values array)
               * @param values An array containing amounts of each token being transferred (order and length must match ids array)
               * @param data Additional data with no specified format
               * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
               */
              function onERC1155BatchReceived(
                  address operator,
                  address from,
                  uint256[] calldata ids,
                  uint256[] calldata values,
                  bytes calldata data
              ) external returns (bytes4);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165Upgradeable.sol";
          /**
           * @dev Required interface of an ERC1155 compliant contract, as defined in the
           * https://eips.ethereum.org/EIPS/eip-1155[EIP].
           *
           * _Available since v3.1._
           */
          interface IERC1155Upgradeable is IERC165Upgradeable {
              /**
               * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
               */
              event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
              /**
               * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
               * transfers.
               */
              event TransferBatch(
                  address indexed operator,
                  address indexed from,
                  address indexed to,
                  uint256[] ids,
                  uint256[] values
              );
              /**
               * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
               * `approved`.
               */
              event ApprovalForAll(address indexed account, address indexed operator, bool approved);
              /**
               * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
               *
               * If an {URI} event was emitted for `id`, the standard
               * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
               * returned by {IERC1155MetadataURI-uri}.
               */
              event URI(string value, uint256 indexed id);
              /**
               * @dev Returns the amount of tokens of token type `id` owned by `account`.
               *
               * Requirements:
               *
               * - `account` cannot be the zero address.
               */
              function balanceOf(address account, uint256 id) external view returns (uint256);
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
               *
               * Requirements:
               *
               * - `accounts` and `ids` must have the same length.
               */
              function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
                  external
                  view
                  returns (uint256[] memory);
              /**
               * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
               *
               * Emits an {ApprovalForAll} event.
               *
               * Requirements:
               *
               * - `operator` cannot be the caller.
               */
              function setApprovalForAll(address operator, bool approved) external;
              /**
               * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
               *
               * See {setApprovalForAll}.
               */
              function isApprovedForAll(address account, address operator) external view returns (bool);
              /**
               * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
               * - `from` must have a balance of tokens of type `id` of at least `amount`.
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
               * acceptance magic value.
               */
              function safeTransferFrom(
                  address from,
                  address to,
                  uint256 id,
                  uint256 amount,
                  bytes calldata data
              ) external;
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
               *
               * Emits a {TransferBatch} event.
               *
               * Requirements:
               *
               * - `ids` and `amounts` must have the same length.
               * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
               * acceptance magic value.
               */
              function safeBatchTransferFrom(
                  address from,
                  address to,
                  uint256[] calldata ids,
                  uint256[] calldata amounts,
                  bytes calldata data
              ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
          pragma solidity ^0.8.1;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @dev Returns true if `account` is a contract.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               *
               * [IMPORTANT]
               * ====
               * You shouldn't rely on `isContract` to protect against flash loan attacks!
               *
               * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
               * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
               * constructor.
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize/address.code.length, which returns 0
                  // for contracts in construction, since the code is only stored at the end
                  // of the constructor execution.
                  return account.code.length > 0;
              }
              /**
               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
               * `recipient`, forwarding all available gas and reverting on errors.
               *
               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
               * of certain opcodes, possibly making contracts go over the 2300 gas limit
               * imposed by `transfer`, making them unable to receive funds via
               * `transfer`. {sendValue} removes this limitation.
               *
               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
               *
               * IMPORTANT: because control is transferred to `recipient`, care must be
               * taken to not create reentrancy vulnerabilities. Consider using
               * {ReentrancyGuard} or the
               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
               */
              function sendValue(address payable recipient, uint256 amount) internal {
                  require(address(this).balance >= amount, "Address: insufficient balance");
                  (bool success, ) = recipient.call{value: amount}("");
                  require(success, "Address: unable to send value, recipient may have reverted");
              }
              /**
               * @dev Performs a Solidity function call using a low level `call`. A
               * plain `call` is an unsafe replacement for a function call: use this
               * function instead.
               *
               * If `target` reverts with a revert reason, it is bubbled up by this
               * function (like regular Solidity function calls).
               *
               * Returns the raw returned data. To convert to the expected return value,
               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
               *
               * Requirements:
               *
               * - `target` must be a contract.
               * - calling `target` with `data` must not revert.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                  return functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                  return verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason 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 {
                      // Look for revert reason and bubble it up if present
                      if (returndata.length > 0) {
                          // The easiest way to bubble the revert reason is using memory via assembly
                          /// @solidity memory-safe-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
          pragma solidity ^0.8.0;
          import "../proxy/utils/Initializable.sol";
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract ContextUpgradeable is Initializable {
              function __Context_init() internal onlyInitializing {
              }
              function __Context_init_unchained() internal onlyInitializing {
              }
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165Upgradeable.sol";
          import "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165Upgradeable {
              function __ERC165_init() internal onlyInitializing {
              }
              function __ERC165_init_unchained() internal onlyInitializing {
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165Upgradeable).interfaceId;
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts 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 IERC165Upgradeable {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           */
          abstract contract ReentrancyGuard {
              // Booleans are more expensive than uint256 or any type that takes up a full
              // word because each write operation emits an extra SLOAD to first read the
              // slot's contents, replace the bits taken up by the boolean, and then write
              // back. This is the compiler's defense against contract upgrades and
              // pointer aliasing, and it cannot be disabled.
              // The values being non-zero value makes deployment a bit more expensive,
              // but in exchange the refund on every call to nonReentrant will be lower in
              // amount. Since refunds are capped to a percentage of the total
              // transaction's gas, it is best to keep them low in cases like this one, to
              // increase the likelihood of the full refund coming into effect.
              uint256 private constant _NOT_ENTERED = 1;
              uint256 private constant _ENTERED = 2;
              uint256 private _status;
              constructor() {
                  _status = _NOT_ENTERED;
              }
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and making it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Library used to query support of an interface declared via {IERC165}.
           *
           * Note that these functions return the actual result of the query: they do not
           * `revert` if an interface is not supported. It is up to the caller to decide
           * what to do in these cases.
           */
          library ERC165Checker {
              // As per the EIP-165 spec, no interface should ever match 0xffffffff
              bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
              /**
               * @dev Returns true if `account` supports the {IERC165} interface,
               */
              function supportsERC165(address account) internal view returns (bool) {
                  // Any contract that implements ERC165 must explicitly indicate support of
                  // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                  return
                      _supportsERC165Interface(account, type(IERC165).interfaceId) &&
                      !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
              }
              /**
               * @dev Returns true if `account` supports the interface defined by
               * `interfaceId`. Support for {IERC165} itself is queried automatically.
               *
               * See {IERC165-supportsInterface}.
               */
              function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                  // query support of both ERC165 as per the spec and support of _interfaceId
                  return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
              }
              /**
               * @dev Returns a boolean array where each value corresponds to the
               * interfaces passed in and whether they're supported or not. This allows
               * you to batch check interfaces for a contract where your expectation
               * is that some interfaces may not be supported.
               *
               * See {IERC165-supportsInterface}.
               *
               * _Available since v3.4._
               */
              function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
                  internal
                  view
                  returns (bool[] memory)
              {
                  // an array of booleans corresponding to interfaceIds and whether they're supported or not
                  bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
                  // query support of ERC165 itself
                  if (supportsERC165(account)) {
                      // query support of each interface in interfaceIds
                      for (uint256 i = 0; i < interfaceIds.length; i++) {
                          interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
                      }
                  }
                  return interfaceIdsSupported;
              }
              /**
               * @dev Returns true if `account` supports all the interfaces defined in
               * `interfaceIds`. Support for {IERC165} itself is queried automatically.
               *
               * Batch-querying can lead to gas savings by skipping repeated checks for
               * {IERC165} support.
               *
               * See {IERC165-supportsInterface}.
               */
              function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                  // query support of ERC165 itself
                  if (!supportsERC165(account)) {
                      return false;
                  }
                  // query support of each interface in _interfaceIds
                  for (uint256 i = 0; i < interfaceIds.length; i++) {
                      if (!_supportsERC165Interface(account, interfaceIds[i])) {
                          return false;
                      }
                  }
                  // all interfaces supported
                  return true;
              }
              /**
               * @notice Query if a contract implements an interface, does not check ERC165 support
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return true if the contract at account indicates support of the interface with
               * identifier interfaceId, false otherwise
               * @dev Assumes that account contains a contract that supports ERC165, otherwise
               * the behavior of this method is undefined. This precondition can be checked
               * with {supportsERC165}.
               * Interface identification is specified in ERC-165.
               */
              function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
                  // prepare call
                  bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
                  // perform static call
                  bool success;
                  uint256 returnSize;
                  uint256 returnValue;
                  assembly {
                      success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
                      returnSize := returndatasize()
                      returnValue := mload(0x00)
                  }
                  return success && returnSize >= 0x20 && returnValue > 0;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev String operations.
           */
          library Strings {
              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
              uint8 private constant _ADDRESS_LENGTH = 20;
              /**
               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  while (value != 0) {
                      digits -= 1;
                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                      value /= 10;
                  }
                  return string(buffer);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
               */
              function toHexString(uint256 value) internal pure returns (string memory) {
                  if (value == 0) {
                      return "0x00";
                  }
                  uint256 temp = value;
                  uint256 length = 0;
                  while (temp != 0) {
                      length++;
                      temp >>= 8;
                  }
                  return toHexString(value, length);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
               */
              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                  bytes memory buffer = new bytes(2 * length + 2);
                  buffer[0] = "0";
                  buffer[1] = "x";
                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                      value >>= 4;
                  }
                  require(value == 0, "Strings: hex length insufficient");
                  return string(buffer);
              }
              /**
               * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
               */
              function toHexString(address addr) internal pure returns (string memory) {
                  return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
          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) {
                  return _values(set._inner);
              }
              // 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 on 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;
              }
          }
          

          File 7 of 7: CreatorOperatorFilterer
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.17;
          import "@manifoldxyz/creator-core-solidity/contracts/extensions/ERC721/IERC721CreatorExtensionApproveTransfer.sol";
          import "@manifoldxyz/creator-core-solidity/contracts/extensions/ERC1155/IERC1155CreatorExtensionApproveTransfer.sol";
          import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol";
          import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
          /// @author: manifold.xyz
          /**
           * Creator controlled Operator Filter for Manifold Creator contracts
           */
          contract CreatorOperatorFilterer is IERC165 {
              using EnumerableSet for EnumerableSet.AddressSet;
              using EnumerableSet for EnumerableSet.Bytes32Set;
              error OperatorNotAllowed(address operator);
              error CodeHashFiltered(address account, bytes32 codeHash);
              event OperatorUpdated(address indexed registrant, address indexed operator, bool indexed filtered);
              event CodeHashUpdated(address indexed registrant, bytes32 indexed codeHash, bool indexed filtered);
              mapping(address => EnumerableSet.AddressSet) private _creatorBlockedOperators;
              mapping(address => EnumerableSet.Bytes32Set) private _creatorFilteredCodeHashes;
              modifier creatorAdminRequired(address creatorContractAddress) {
                  require(IAdminControl(creatorContractAddress).isAdmin(msg.sender), "Wallet is not an admin");
                  _;
              }
              /**
               * @dev Get list of blocked operator addresses for a given creator contract
               */
              function getBlockedOperators(address creatorContractAddress) external view returns (address[] memory result) {
                  EnumerableSet.AddressSet storage set = _creatorBlockedOperators[creatorContractAddress];
                  result = new address[](set.length());
                  for (uint i; i < set.length(); ++i) {
                      result[i] = set.at(i);
                  }
              }
              /**
               * @dev Get list of blocked operator code hashes for a given creator contract
               */
              function getBlockedOperatorHashes(address creatorContractAddress) external view returns (bytes32[] memory result) {
                  EnumerableSet.Bytes32Set storage set = _creatorFilteredCodeHashes[creatorContractAddress];
                  result = new bytes32[](set.length());
                  for (uint i; i < set.length(); ++i) {
                      result[i] = set.at(i);
                  }
              }
              /**
               * @dev Configure list of operator addresses for a given creator contract
               *      Only an admin of the creator contract can make this call
               */
              function configureBlockedOperators(address creator, address[] memory operators, bool[] memory blocked) public creatorAdminRequired(creator) {
                  require(operators.length == blocked.length, "Mismatch input length");
                  for (uint i; i < operators.length; ++i) {
                      address operator = operators[i];
                      bool blockedValue = blocked[i];
                      if (blockedValue) {
                          _creatorBlockedOperators[creator].add(operator);
                      } else {
                          _creatorBlockedOperators[creator].remove(operator);
                      }
                      emit OperatorUpdated(creator, operator, blockedValue);
                  }
              }
              /**
               * @dev Configure list of operator code hashes for a given creator contract
               *      Only an admin of the creator contract can make this call
               */
              function configureBlockedOperatorHashes(address creator, bytes32[] memory hashes, bool[] memory blocked) public creatorAdminRequired(creator) {
                  require(hashes.length == blocked.length, "Mismatch input length");
                  
                  for (uint i; i < hashes.length; ++i) {
                      bytes32 hash_ = hashes[i];
                      bool blockedValue = blocked[i];
                      if (blockedValue) {
                          _creatorFilteredCodeHashes[creator].add(hash_);
                      } else {
                          _creatorFilteredCodeHashes[creator].remove(hash_);
                      }
                      emit CodeHashUpdated(creator, hash_, blockedValue);
                  }
              }
              /**
               * @dev Configure list of operator addresses and code hashes for a given creator contract
               *      Only an admin of the creator contract can make this call
               */
              function configureBlockedOperatorsAndHashes(address creator, address[] memory operators, bool[] memory blockedOperators, bytes32[] memory hashes, bool[] memory blockedHashes) public creatorAdminRequired(creator) {
                  configureBlockedOperators(creator, operators, blockedOperators);
                  configureBlockedOperatorHashes(creator, hashes, blockedHashes);
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override (IERC165) returns (bool) {
                  return interfaceId == type(IERC721CreatorExtensionApproveTransfer).interfaceId
                      || interfaceId == type(IERC1155CreatorExtensionApproveTransfer).interfaceId
                      || interfaceId == type(IERC165).interfaceId;
              }
              /**
               * @dev ERC1155: Called by creator contract to approve a transfer
               */
              function approveTransfer(address operator, address from, address, uint256[] calldata, uint256[] calldata)
                  external
                  view
                  returns (bool)
              {
                  return isOperatorAllowed(operator, from);
              }
              /**
               * @dev ERC721: Called by creator contract to approve a transfer
               */
              function approveTransfer(address operator, address from, address, uint256) external view returns (bool) {
                  return isOperatorAllowed(operator, from);
              }
              /**
               * @dev Check OperatorFiltererRegistry to see if operator is approved
               */
              function isOperatorAllowed(address operator, address from) internal view returns (bool) {
                  if (from != operator) {
                      if (_creatorBlockedOperators[msg.sender].contains(operator)) {
                          revert OperatorNotAllowed(operator);
                      }
                      if (operator.code.length > 0) {
                          bytes32 codeHash = operator.codehash;
                          if (_creatorFilteredCodeHashes[msg.sender].contains(codeHash)) {
                              revert CodeHashFiltered(operator, codeHash);
                          }
                      }
                  }
                  return true;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * Implement this if you want your extension to approve a transfer
           */
          interface IERC1155CreatorExtensionApproveTransfer is IERC165 {
              /**
               * @dev Set whether or not the creator contract will check the extension for approval of token transfer
               */
              function setApproveTransfer(address creator, bool enabled) external;
              /**
               * @dev Called by creator contract to approve a transfer
               */
              function approveTransfer(address operator, address from, address to, uint256[] calldata tokenIds, uint256[] calldata amounts) external returns (bool);
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * Implement this if you want your extension to approve a transfer
           */
          interface IERC721CreatorExtensionApproveTransfer is IERC165 {
              /**
               * @dev Set whether or not the creator will check the extension for approval of token transfer
               */
              function setApproveTransfer(address creator, bool enabled) external;
              /**
               * @dev Called by creator contract to approve a transfer
               */
              function approveTransfer(address operator, address from, address to, uint256 tokenId) external returns (bool);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /// @author: manifold.xyz
          import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
          /**
           * @dev Interface for admin control
           */
          interface IAdminControl is IERC165 {
              event AdminApproved(address indexed account, address indexed sender);
              event AdminRevoked(address indexed account, address indexed sender);
              /**
               * @dev gets address of all admins
               */
              function getAdmins() external view returns (address[] memory);
              /**
               * @dev add an admin.  Can only be called by contract owner.
               */
              function approveAdmin(address admin) external;
              /**
               * @dev remove an admin.  Can only be called by contract owner.
               */
              function revokeAdmin(address admin) external;
              /**
               * @dev checks whether or not given address is an admin
               * Returns True if they are
               */
              function isAdmin(address admin) external view returns (bool);
          }// SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
          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) {
                  return _values(set._inner);
              }
              // 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 on 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;
              }
          }