ETH Price: $3,084.59 (+0.20%)
Gas: 8 Gwei

Transaction Decoder

Block:
15127846 at Jul-12-2022 12:39:06 PM +UTC
Transaction Fee:
0.002958422291014026 ETH $9.13
Gas Used:
156,614 Gas / 18.889896759 Gwei

Emitted Events:

166 Seaport.OrderFulfilled( orderHash=B1833653215160CE141E9FA3D0D61B4FFA7091C01D5C2C183366C7F2AC82C097, offerer=0x2c44a63384cddf86b9213a9558351c30260e8939, zone=PausableZone, recipient=[Sender] 0x5e8053f3b43ee366640d75cafc0572f442b93fcb, offer=, consideration= )
167 ArtsyMonke.Approval( owner=0x2c44a63384cddf86b9213a9558351c30260e8939, approved=0x00000000...000000000, tokenId=4289 )
168 ArtsyMonke.Transfer( from=0x2c44a63384cddf86b9213a9558351c30260e8939, to=[Sender] 0x5e8053f3b43ee366640d75cafc0572f442b93fcb, tokenId=4289 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...169EdE581
(Seaport 1.1)
0x2C44A633...0260e8939 0.166634128883401563 Eth0.168821628883401563 Eth0.0021875
0x581bd95c...90256C5a0
(Artsy Monke: Deployer)
1.419765136431384772 Eth1.420015136431384772 Eth0.00025
0x5E8053f3...442b93fcB
0.106826283614853988 Eth
Nonce: 166
0.101367861323839962 Eth
Nonce: 167
0.005458422291014026
(Miner: 0x646...087)
30.883148829926632574 Eth30.883540364926632574 Eth0.000391535
0x8De9C5A0...7BCC5BC90
(OpenSea: Fees)
1,199.043482337606397027 Eth1,199.043544837606397027 Eth0.0000625
0xA4bcD3b7...1565561Bc

Execution Trace

ETH 0.0025 Seaport.fulfillBasicOrder( parameters=[{name:considerationToken, type:address, order:1, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:considerationIdentifier, type:uint256, order:2, indexed:false, value:0, valueString:0}, {name:considerationAmount, type:uint256, order:3, indexed:false, value:2187500000000000, valueString:2187500000000000}, {name:offerer, type:address, order:4, indexed:false, value:0x2C44A63384CdDF86b9213A9558351c30260e8939, valueString:0x2C44A63384CdDF86b9213A9558351c30260e8939}, {name:zone, type:address, order:5, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {name:offerToken, type:address, order:6, indexed:false, value:0xA4bcD3b7F141Ba1f08F36033fdfCe691565561Bc, valueString:0xA4bcD3b7F141Ba1f08F36033fdfCe691565561Bc}, {name:offerIdentifier, type:uint256, order:7, indexed:false, value:4289, valueString:4289}, {name:offerAmount, type:uint256, order:8, indexed:false, value:1, valueString:1}, {name:basicOrderType, type:uint8, order:9, indexed:false, value:2, valueString:2}, {name:startTime, type:uint256, order:10, indexed:false, value:1657628975, valueString:1657628975}, {name:endTime, type:uint256, order:11, indexed:false, value:1660307375, valueString:1660307375}, {name:zoneHash, type:bytes32, order:12, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:13, indexed:false, value:56072342071915922, valueString:56072342071915922}, {name:offererConduitKey, type:bytes32, order:14, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:fulfillerConduitKey, type:bytes32, order:15, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalAdditionalRecipients, type:uint256, order:16, indexed:false, value:2, valueString:2}, {name:additionalRecipients, type:tuple[], order:17, indexed:false}, {name:signature, type:bytes, order:18, indexed:false, value:0x5C3222D5E6124276AF1D47D478820AD43C7031B1D01AE09CC6A1C09ED8639C0A481BB2F7670A10A532DAE0DDE87F76ABCA229C4797EFCC7DB66A90A69AF0CC661C, valueString:0x5C3222D5E6124276AF1D47D478820AD43C7031B1D01AE09CC6A1C09ED8639C0A481BB2F7670A10A532DAE0DDE87F76ABCA229C4797EFCC7DB66A90A69AF0CC661C}] ) => ( fulfilled=True )
  • PausableZone.isValidOrder( orderHash=B1833653215160CE141E9FA3D0D61B4FFA7091C01D5C2C183366C7F2AC82C097, caller=0x5E8053f3B43EE366640D75CAfC0572F442b93fcB, offerer=0x2C44A63384CdDF86b9213A9558351c30260e8939, zoneHash=0000000000000000000000000000000000000000000000000000000000000000 )
  • Null: 0x000...001.84eca5d5( )
  • Conduit.execute( transfers= ) => ( transfers= )
    • ArtsyMonke.transferFrom( from=0x2C44A63384CdDF86b9213A9558351c30260e8939, to=0x5E8053f3B43EE366640D75CAfC0572F442b93fcB, tokenId=4289 )
    • ETH 0.0000625 OpenSea: Fees.CALL( )
    • ETH 0.00025 Artsy Monke: Deployer.CALL( )
    • ETH 0.0021875 0x2c44a63384cddf86b9213a9558351c30260e8939.CALL( )
      fulfillBasicOrder[Consideration (ln:9074)]
      File 1 of 4: 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 4: ArtsyMonke
      /**
       *Submitted for verification at Etherscan.io on 2022-06-15
      */
      
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      
      
      library Strings {
          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
      
          /**
           * @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);
          }
      }
      
      library Counters {
          struct Counter {
              // This variable should never be directly accessed by users of the library: interactions must be restricted to
              // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
              // this feature: see https://github.com/ethereum/solidity/issues/4637
              uint256 _value; // default: 0
          }
      
          function current(Counter storage counter) internal view returns (uint256) {
              return counter._value;
          }
      
          function increment(Counter storage counter) internal {
              unchecked {
                  counter._value += 1;
              }
          }
      
          function decrement(Counter storage counter) internal {
              uint256 value = counter._value;
              require(value > 0, "Counter: decrement overflow");
              unchecked {
                  counter._value = value - 1;
              }
          }
      
          function reset(Counter storage counter) internal {
              counter._value = 0;
          }
      }
      
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      
      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
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
      
              uint256 size;
              assembly {
                  size := extcodesize(account)
              }
              return size > 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 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) {
              require(isContract(target), "Address: delegate call to non-contract");
      
              (bool success, bytes memory returndata) = target.delegatecall(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
      
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      
      interface IERC721Receiver {
          /**
           * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
           * by `operator` from `from`, this function is called.
           *
           * It must return its Solidity selector to confirm the token transfer.
           * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
           *
           * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
           */
          function onERC721Received(
              address operator,
              address from,
              uint256 tokenId,
              bytes calldata data
          ) external returns (bytes4);
      }
      
      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);
      }
      
      abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
              return interfaceId == type(IERC165).interfaceId;
          }
      }
      
      interface IERC721 is IERC165 {
          /**
           * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
           */
          event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
      
          /**
           * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
           */
          event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
      
          /**
           * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
           */
          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
      
          /**
           * @dev Returns the number of tokens in ``owner``'s account.
           */
          function balanceOf(address owner) external view returns (uint256 balance);
      
          /**
           * @dev Returns the owner of the `tokenId` token.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           */
          function ownerOf(uint256 tokenId) external view returns (address owner);
      
          /**
           * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
           * are aware of the ERC721 protocol to prevent tokens from being forever locked.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external;
      
          /**
           * @dev Transfers `tokenId` token from `from` to `to`.
           *
           * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external;
      
          /**
           * @dev Gives permission to `to` to transfer `tokenId` token to another account.
           * The approval is cleared when the token is transferred.
           *
           * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
           *
           * Requirements:
           *
           * - The caller must own the token or be an approved operator.
           * - `tokenId` must exist.
           *
           * Emits an {Approval} event.
           */
          function approve(address to, uint256 tokenId) external;
      
          /**
           * @dev Returns the account approved for `tokenId` token.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           */
          function getApproved(uint256 tokenId) external view returns (address operator);
      
          /**
           * @dev Approve or remove `operator` as an operator for the caller.
           * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
           *
           * Requirements:
           *
           * - The `operator` cannot be the caller.
           *
           * Emits an {ApprovalForAll} event.
           */
          function setApprovalForAll(address operator, bool _approved) external;
      
          /**
           * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
           *
           * See {setApprovalForAll}
           */
          function isApprovedForAll(address owner, address operator) external view returns (bool);
      
          /**
           * @dev Safely transfers `tokenId` token from `from` to `to`.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes calldata data
          ) external;
      }
      
      interface IERC721Metadata is IERC721 {
          /**
           * @dev Returns the token collection name.
           */
          function name() external view returns (string memory);
      
          /**
           * @dev Returns the token collection symbol.
           */
          function symbol() external view returns (string memory);
      
          /**
           * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
           */
          function tokenURI(uint256 tokenId) external view returns (string memory);
      }
      
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
          }
      
          /**
           * @dev Returns the substraction of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
          }
      
          /**
           * @dev Returns the division of two unsigned integers, with a division by zero flag.
           *
           * _Available since v3.4._
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
           *
           * _Available since v3.4._
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
          }
      
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           *
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              return a + b;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return a - b;
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           *
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              return a * b;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers, reverting on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator.
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return a % b;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {trySub}.
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(
              uint256 a,
              uint256 b,
              string memory errorMessage
          ) internal pure returns (uint256) {
              unchecked {
                  require(b <= a, errorMessage);
                  return a - b;
              }
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers, reverting with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(
              uint256 a,
              uint256 b,
              string memory errorMessage
          ) internal pure returns (uint256) {
              unchecked {
                  require(b > 0, errorMessage);
                  return a / b;
              }
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting with custom message when dividing by zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryMod}.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(
              uint256 a,
              uint256 b,
              string memory errorMessage
          ) internal pure returns (uint256) {
              unchecked {
                  require(b > 0, errorMessage);
                  return a % b;
              }
          }
      }
      
      contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
          using Address for address;
          using Strings for uint256;
      
          // Token name
          string private _name;
      
          // Token symbol
          string private _symbol;
      
          // Mapping from token ID to owner address
          mapping(uint256 => address) private _owners;
      
          // Mapping owner address to token count
          mapping(address => uint256) private _balances;
      
          // Mapping from token ID to approved address
          mapping(uint256 => address) private _tokenApprovals;
      
          // Mapping from owner to operator approvals
          mapping(address => mapping(address => bool)) private _operatorApprovals;
      
          /**
           * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
           */
          constructor(string memory name_, string memory symbol_) {
              _name = name_;
              _symbol = symbol_;
          }
      
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
              return
                  interfaceId == type(IERC721).interfaceId ||
                  interfaceId == type(IERC721Metadata).interfaceId ||
                  super.supportsInterface(interfaceId);
          }
      
          /**
           * @dev See {IERC721-balanceOf}.
           */
          function balanceOf(address owner) public view virtual override returns (uint256) {
              require(owner != address(0), "ERC721: balance query for the zero address");
              return _balances[owner];
          }
      
          /**
           * @dev See {IERC721-ownerOf}.
           */
          function ownerOf(uint256 tokenId) public view virtual override returns (address) {
              address owner = _owners[tokenId];
              require(owner != address(0), "ERC721: owner query for nonexistent token");
              return owner;
          }
      
          /**
           * @dev See {IERC721Metadata-name}.
           */
          function name() public view virtual override returns (string memory) {
              return _name;
          }
      
          /**
           * @dev See {IERC721Metadata-symbol}.
           */
          function symbol() public view virtual override returns (string memory) {
              return _symbol;
          }
      
          /**
           * @dev See {IERC721Metadata-tokenURI}.
           */
          function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
              require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
      
              string memory baseURI = _baseURI();
              return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
          }
      
          /**
           * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
           * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
           * by default, can be overriden in child contracts.
           */
          function _baseURI() internal view virtual returns (string memory) {
              return "";
          }
      
          /**
           * @dev See {IERC721-approve}.
           */
          function approve(address to, uint256 tokenId) public virtual override {
              address owner = ERC721.ownerOf(tokenId);
              require(to != owner, "ERC721: approval to current owner");
      
              require(
                  _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                  "ERC721: approve caller is not owner nor approved for all"
              );
      
              _approve(to, tokenId);
          }
      
          /**
           * @dev See {IERC721-getApproved}.
           */
          function getApproved(uint256 tokenId) public view virtual override returns (address) {
              require(_exists(tokenId), "ERC721: approved query for nonexistent token");
      
              return _tokenApprovals[tokenId];
          }
      
          /**
           * @dev See {IERC721-setApprovalForAll}.
           */
          function setApprovalForAll(address operator, bool approved) public virtual override {
              require(operator != _msgSender(), "ERC721: approve to caller");
      
              _operatorApprovals[_msgSender()][operator] = approved;
              emit ApprovalForAll(_msgSender(), operator, approved);
          }
      
          /**
           * @dev See {IERC721-isApprovedForAll}.
           */
          function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
              return _operatorApprovals[owner][operator];
          }
      
          /**
           * @dev See {IERC721-transferFrom}.
           */
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public virtual override {
              //solhint-disable-next-line max-line-length
              require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
      
              _transfer(from, to, tokenId);
          }
      
          /**
           * @dev See {IERC721-safeTransferFrom}.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public virtual override {
              safeTransferFrom(from, to, tokenId, "");
          }
      
          /**
           * @dev See {IERC721-safeTransferFrom}.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) public virtual override {
              require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
              _safeTransfer(from, to, tokenId, _data);
          }
      
          /**
           * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
           * are aware of the ERC721 protocol to prevent tokens from being forever locked.
           *
           * `_data` is additional data, it has no specified format and it is sent in call to `to`.
           *
           * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
           * implement alternative mechanisms to perform token transfer, such as signature-based.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function _safeTransfer(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) internal virtual {
              _transfer(from, to, tokenId);
              require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
          }
      
          /**
           * @dev Returns whether `tokenId` exists.
           *
           * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
           *
           * Tokens start existing when they are minted (`_mint`),
           * and stop existing when they are burned (`_burn`).
           */
          function _exists(uint256 tokenId) internal view virtual returns (bool) {
              return _owners[tokenId] != address(0);
          }
      
          /**
           * @dev Returns whether `spender` is allowed to manage `tokenId`.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           */
          function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
              require(_exists(tokenId), "ERC721: operator query for nonexistent token");
              address owner = ERC721.ownerOf(tokenId);
              return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
          }
      
          /**
           * @dev Safely mints `tokenId` and transfers it to `to`.
           *
           * Requirements:
           *
           * - `tokenId` must not exist.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function _safeMint(address to, uint256 tokenId) internal virtual {
              _safeMint(to, tokenId, "");
          }
      
          /**
           * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
           * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
           */
          function _safeMint(
              address to,
              uint256 tokenId,
              bytes memory _data
          ) internal virtual {
              _mint(to, tokenId);
              require(
                  _checkOnERC721Received(address(0), to, tokenId, _data),
                  "ERC721: transfer to non ERC721Receiver implementer"
              );
          }
      
          /**
           * @dev Mints `tokenId` and transfers it to `to`.
           *
           * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
           *
           * Requirements:
           *
           * - `tokenId` must not exist.
           * - `to` cannot be the zero address.
           *
           * Emits a {Transfer} event.
           */
          function _mint(address to, uint256 tokenId) internal virtual {
              require(to != address(0), "ERC721: mint to the zero address");
              require(!_exists(tokenId), "ERC721: token already minted");
      
              _beforeTokenTransfer(address(0), to, tokenId);
      
              _balances[to] += 1;
              _owners[tokenId] = to;
      
              emit Transfer(address(0), to, tokenId);
          }
      
          /**
           * @dev Destroys `tokenId`.
           * The approval is cleared when the token is burned.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           *
           * Emits a {Transfer} event.
           */
          function _burn(uint256 tokenId) internal virtual {
              address owner = ERC721.ownerOf(tokenId);
      
              _beforeTokenTransfer(owner, address(0), tokenId);
      
              // Clear approvals
              _approve(address(0), tokenId);
      
              _balances[owner] -= 1;
              delete _owners[tokenId];
      
              emit Transfer(owner, address(0), tokenId);
          }
      
          /**
           * @dev Transfers `tokenId` from `from` to `to`.
           *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           * - `tokenId` token must be owned by `from`.
           *
           * Emits a {Transfer} event.
           */
          function _transfer(
              address from,
              address to,
              uint256 tokenId
          ) internal virtual {
              require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
              require(to != address(0), "ERC721: transfer to the zero address");
      
              _beforeTokenTransfer(from, to, tokenId);
      
              // Clear approvals from the previous owner
              _approve(address(0), tokenId);
      
              _balances[from] -= 1;
              _balances[to] += 1;
              _owners[tokenId] = to;
      
              emit Transfer(from, to, tokenId);
          }
      
          /**
           * @dev Approve `to` to operate on `tokenId`
           *
           * Emits a {Approval} event.
           */
          function _approve(address to, uint256 tokenId) internal virtual {
              _tokenApprovals[tokenId] = to;
              emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
          }
      
          /**
           * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
           * The call is not executed if the target address is not a contract.
           *
           * @param from address representing the previous owner of the given token ID
           * @param to target address that will receive the tokens
           * @param tokenId uint256 ID of the token to be transferred
           * @param _data bytes optional data to send along with the call
           * @return bool whether the call correctly returned the expected magic value
           */
          function _checkOnERC721Received(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) private returns (bool) {
              if (to.isContract()) {
                  try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                      return retval == IERC721Receiver.onERC721Received.selector;
                  } catch (bytes memory reason) {
                      if (reason.length == 0) {
                          revert("ERC721: transfer to non ERC721Receiver implementer");
                      } else {
                          assembly {
                              revert(add(32, reason), mload(reason))
                          }
                      }
                  }
              } else {
                  return true;
              }
          }
      
          /**
           * @dev Hook that is called before any token transfer. This includes minting
           * and burning.
           *
           * Calling conditions:
           *
           * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
           * transferred to `to`.
           * - When `from` is zero, `tokenId` will be minted for `to`.
           * - When `to` is zero, ``from``'s `tokenId` will be burned.
           * - `from` and `to` are never both zero.
           *
           * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
           */
          function _beforeTokenTransfer(
              address from,
              address to,
              uint256 tokenId
          ) internal virtual {}
      }
      
      abstract contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
              _setOwner(_msgSender());
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              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 {
              _setOwner(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");
              _setOwner(newOwner);
          }
      
          function _setOwner(address newOwner) private {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      
      contract ArtsyMonke is ERC721, Ownable
      {
          using Counters for Counters.Counter;
          using SafeMath for uint256;
      
          uint256 public price = .01 ether;
          uint256 public maxSupply = 10000;
          uint256 private maxMint = 50;
      
          string private customBaseURI;
          string private baseExtension;
      
          bool public mintOpen = false;
      
          Counters.Counter private _tokenSupply;
      
          constructor(string memory _customBaseURI) ERC721("Artsy Monke", "ArtsyMonke")  {
              customBaseURI = _customBaseURI;
          }
      
          function totalSupply() public view returns (uint256) {
              return _tokenSupply.current();
          }
      
          function mintBulk(uint256 numberOfMints, address mintAddress) public payable onlyOwner{
              uint256 supply = _tokenSupply.current();
             for(uint256 i = 1; i <= numberOfMints; i++){
                  _safeMint(mintAddress, supply + i);
                  _tokenSupply.increment();
              }
          }
      
          function mint(uint256 numberOfMints) external payable {
              uint256 supply = _tokenSupply.current();
              require(mintOpen, "Sale Needs To Be Active");
              require(numberOfMints > 0 && numberOfMints <= maxMint, "Invalid purchase amount");
              require(supply.add(numberOfMints) <= maxSupply, "Payment exceeds total supply");
      
             for(uint256 i = 1; i <= numberOfMints; i++){
                  _safeMint(msg.sender, supply + i);
                  _tokenSupply.increment();
              }
          }
      
          function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
              require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
              string memory currentBaseURI = _baseURI();
              return bytes(currentBaseURI).length > 0
                  ? string(abi.encodePacked(currentBaseURI, Strings.toString(tokenId), baseExtension))
                  : "";
          }
      
          function toggleSale() public onlyOwner {
              mintOpen = !mintOpen;
          }
      
          function _baseURI() internal view virtual override returns (string memory) {
              return customBaseURI;
          }
      
          function setBaseURI(string calldata _newBaseURI) external onlyOwner {
              customBaseURI = _newBaseURI;
          }
      
          function setMaxMint(uint256 _maxMint) external onlyOwner {
              maxMint = _maxMint;
          }
      
          function withdraw() public onlyOwner {
              uint256 balance = address(this).balance;
              payable(msg.sender).transfer(balance);
          }
      
      }

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