ETH Price: $2,467.94 (+3.10%)

Transaction Decoder

Block:
16284264 at Dec-28-2022 03:51:35 PM +UTC
Transaction Fee:
0.002995445869680027 ETH $7.39
Gas Used:
148,249 Gas / 20.205504723 Gwei

Emitted Events:

253 Seaport.OrderFulfilled( orderHash=2337A0EABD0ABEA52EB4FF5D7490CE2D2D8568061F5EA2E818DE630550BD232B, offerer=0x80e45cde985464ca2f9f6c86ded3bfd682d30f4a, zone=PausableZone, recipient=[Sender] 0xaaceaca8836a2624ee782b6365737ca181db72ae, offer=, consideration= )
254 0x8ff1523091c9517bc328223d50b52ef450200339.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x00000000000000000000000080e45cde985464ca2f9f6c86ded3bfd682d30f4a, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000955 )
255 0x8ff1523091c9517bc328223d50b52ef450200339.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000080e45cde985464ca2f9f6c86ded3bfd682d30f4a, 0x000000000000000000000000aaceaca8836a2624ee782b6365737ca181db72ae, 0x0000000000000000000000000000000000000000000000000000000000000955 )
256 GnosisSafeProxy.0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d( 0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d, 0x00000000000000000000000000000000006c3852cbef3e08e8df289169ede581, 00000000000000000000000000000000000000000000000000628fa821ae6800 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...169EdE581
(Seaport 1.1)
0x0000a26b...000fAa719
78.104586779372166718 Eth78.113834279372166718 Eth0.0092475
0x3A808845...fde796DBC 1.383390219161308964 Eth1.411132719161308964 Eth0.0277425
0x80e45CdE...682d30F4a 0.006495075123991531 Eth0.339405075123991531 Eth0.33291
0x8ff15230...450200339
(beaverbuild)
126.880296866921813195 Eth126.880519240421813195 Eth0.0002223735
0xAACEaca8...181DB72Ae
2.554919190949978107 Eth
Nonce: 481
2.18202374508029808 Eth
Nonce: 482
0.372895445869680027

Execution Trace

ETH 0.3699 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:332910000000000000, valueString:332910000000000000}, {name:offerer, type:address, order:4, indexed:false, value:0x80e45CdE985464ca2F9f6C86deD3bfd682d30F4a, valueString:0x80e45CdE985464ca2F9f6C86deD3bfd682d30F4a}, {name:zone, type:address, order:5, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {name:offerToken, type:address, order:6, indexed:false, value:0x8ff1523091c9517BC328223D50b52Ef450200339, valueString:0x8ff1523091c9517BC328223D50b52Ef450200339}, {name:offerIdentifier, type:uint256, order:7, indexed:false, value:2389, valueString:2389}, {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:1672242216, valueString:1672242216}, {name:endTime, type:uint256, order:11, indexed:false, value:1672501416, valueString:1672501416}, {name:zoneHash, type:bytes32, order:12, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:13, indexed:false, value:24446860302761739304752683030156737591518664810215442929805072821111460706830, valueString:24446860302761739304752683030156737591518664810215442929805072821111460706830}, {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:0xFECB4CD074BC6A8E64AB04A0E37D6DBB04D95899CFC12EB5DB17F68B152CA46668A4DEEFAC357FA7C1826B3A7A2C3E2E7F137378CF8E029D82EF18C8D529FA651B, valueString:0xFECB4CD074BC6A8E64AB04A0E37D6DBB04D95899CFC12EB5DB17F68B152CA46668A4DEEFAC357FA7C1826B3A7A2C3E2E7F137378CF8E029D82EF18C8D529FA651B}] ) => ( fulfilled=True )
  • PausableZone.isValidOrder( orderHash=2337A0EABD0ABEA52EB4FF5D7490CE2D2D8568061F5EA2E818DE630550BD232B, caller=0xAACEaca8836A2624eE782b6365737CA181DB72Ae, offerer=0x80e45CdE985464ca2F9f6C86deD3bfd682d30F4a, zoneHash=0000000000000000000000000000000000000000000000000000000000000000 )
  • Null: 0x000...001.df380c1e( )
  • Conduit.execute( transfers= ) => ( transfers= )
    • RugGenesis NFT: ✺RUGNFT Token.23b872dd( )
      • 0x477c17e53a5f5bc17a6fd54f94219713fda0f562.23b872dd( )
        • 0x54b2b5a9835704ebecc9ae13feb937f89fffe124.601ef880( )
        • ETH 0.0092475 PayableProxy.CALL( )
        • ETH 0.0277425 GnosisSafeProxy.CALL( )
          • ETH 0.0277425 GnosisSafe.DELEGATECALL( )
          • ETH 0.33291 0x80e45cde985464ca2f9f6c86ded3bfd682d30f4a.CALL( )
            fulfillBasicOrder[Consideration (ln:9074)]
            File 1 of 6: 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 6: GnosisSafeProxy
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            
            /// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
            /// @author Richard Meissner - <[email protected]>
            interface IProxy {
                function masterCopy() external view returns (address);
            }
            
            /// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
            /// @author Stefan George - <[email protected]>
            /// @author Richard Meissner - <[email protected]>
            contract GnosisSafeProxy {
                // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
                // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
                address internal singleton;
            
                /// @dev Constructor function sets address of singleton contract.
                /// @param _singleton Singleton address.
                constructor(address _singleton) {
                    require(_singleton != address(0), "Invalid singleton address provided");
                    singleton = _singleton;
                }
            
                /// @dev Fallback function forwards all transactions and returns all received return data.
                fallback() external payable {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                        // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                        if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                            mstore(0, _singleton)
                            return(0, 0x20)
                        }
                        calldatacopy(0, 0, calldatasize())
                        let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
                        returndatacopy(0, 0, returndatasize())
                        if eq(success, 0) {
                            revert(0, returndatasize())
                        }
                        return(0, returndatasize())
                    }
                }
            }
            
            /// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
            /// @author Stefan George - <[email protected]>
            contract GnosisSafeProxyFactory {
                event ProxyCreation(GnosisSafeProxy proxy, address singleton);
            
                /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
                /// @param singleton Address of singleton contract.
                /// @param data Payload for message call sent to new proxy contract.
                function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
                    proxy = new GnosisSafeProxy(singleton);
                    if (data.length > 0)
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
                                revert(0, 0)
                            }
                        }
                    emit ProxyCreation(proxy, singleton);
                }
            
                /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
                function proxyRuntimeCode() public pure returns (bytes memory) {
                    return type(GnosisSafeProxy).runtimeCode;
                }
            
                /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
                function proxyCreationCode() public pure returns (bytes memory) {
                    return type(GnosisSafeProxy).creationCode;
                }
            
                /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
                ///      This method is only meant as an utility to be called from other methods
                /// @param _singleton Address of singleton contract.
                /// @param initializer Payload for message call sent to new proxy contract.
                /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
                function deployProxyWithNonce(
                    address _singleton,
                    bytes memory initializer,
                    uint256 saltNonce
                ) internal returns (GnosisSafeProxy proxy) {
                    // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
                    bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
                    bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
                    }
                    require(address(proxy) != address(0), "Create2 call failed");
                }
            
                /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
                /// @param _singleton Address of singleton contract.
                /// @param initializer Payload for message call sent to new proxy contract.
                /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
                function createProxyWithNonce(
                    address _singleton,
                    bytes memory initializer,
                    uint256 saltNonce
                ) public returns (GnosisSafeProxy proxy) {
                    proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                    if (initializer.length > 0)
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
                                revert(0, 0)
                            }
                        }
                    emit ProxyCreation(proxy, _singleton);
                }
            
                /// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
                /// @param _singleton Address of singleton contract.
                /// @param initializer Payload for message call sent to new proxy contract.
                /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
                /// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
                function createProxyWithCallback(
                    address _singleton,
                    bytes memory initializer,
                    uint256 saltNonce,
                    IProxyCreationCallback callback
                ) public returns (GnosisSafeProxy proxy) {
                    uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
                    proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
                    if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
                }
            
                /// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
                ///      This method is only meant for address calculation purpose when you use an initializer that would revert,
                ///      therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
                /// @param _singleton Address of singleton contract.
                /// @param initializer Payload for message call sent to new proxy contract.
                /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
                function calculateCreateProxyWithNonceAddress(
                    address _singleton,
                    bytes calldata initializer,
                    uint256 saltNonce
                ) external returns (GnosisSafeProxy proxy) {
                    proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                    revert(string(abi.encodePacked(proxy)));
                }
            }
            
            interface IProxyCreationCallback {
                function proxyCreated(
                    GnosisSafeProxy proxy,
                    address _singleton,
                    bytes calldata initializer,
                    uint256 saltNonce
                ) external;
            }

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

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

            File 6 of 6: GnosisSafe
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "./base/ModuleManager.sol";
            import "./base/OwnerManager.sol";
            import "./base/FallbackManager.sol";
            import "./base/GuardManager.sol";
            import "./common/EtherPaymentFallback.sol";
            import "./common/Singleton.sol";
            import "./common/SignatureDecoder.sol";
            import "./common/SecuredTokenTransfer.sol";
            import "./common/StorageAccessible.sol";
            import "./interfaces/ISignatureValidator.sol";
            import "./external/GnosisSafeMath.sol";
            /// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
            /// @author Stefan George - <[email protected]>
            /// @author Richard Meissner - <[email protected]>
            contract GnosisSafe is
                EtherPaymentFallback,
                Singleton,
                ModuleManager,
                OwnerManager,
                SignatureDecoder,
                SecuredTokenTransfer,
                ISignatureValidatorConstants,
                FallbackManager,
                StorageAccessible,
                GuardManager
            {
                using GnosisSafeMath for uint256;
                string public constant VERSION = "1.3.0";
                // keccak256(
                //     "EIP712Domain(uint256 chainId,address verifyingContract)"
                // );
                bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
                // keccak256(
                //     "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
                // );
                bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
                event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler);
                event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
                event SignMsg(bytes32 indexed msgHash);
                event ExecutionFailure(bytes32 txHash, uint256 payment);
                event ExecutionSuccess(bytes32 txHash, uint256 payment);
                uint256 public nonce;
                bytes32 private _deprecatedDomainSeparator;
                // Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
                mapping(bytes32 => uint256) public signedMessages;
                // Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
                mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
                // This constructor ensures that this contract can only be used as a master copy for Proxy contracts
                constructor() {
                    // By setting the threshold it is not possible to call setup anymore,
                    // so we create a Safe with 0 owners and threshold 1.
                    // This is an unusable Safe, perfect for the singleton
                    threshold = 1;
                }
                /// @dev Setup function sets initial storage of contract.
                /// @param _owners List of Safe owners.
                /// @param _threshold Number of required confirmations for a Safe transaction.
                /// @param to Contract address for optional delegate call.
                /// @param data Data payload for optional delegate call.
                /// @param fallbackHandler Handler for fallback calls to this contract
                /// @param paymentToken Token that should be used for the payment (0 is ETH)
                /// @param payment Value that should be paid
                /// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
                function setup(
                    address[] calldata _owners,
                    uint256 _threshold,
                    address to,
                    bytes calldata data,
                    address fallbackHandler,
                    address paymentToken,
                    uint256 payment,
                    address payable paymentReceiver
                ) external {
                    // setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice
                    setupOwners(_owners, _threshold);
                    if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
                    // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
                    setupModules(to, data);
                    if (payment > 0) {
                        // To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
                        // baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
                        handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
                    }
                    emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
                }
                /// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
                ///      Note: The fees are always transferred, even if the user transaction fails.
                /// @param to Destination address of Safe transaction.
                /// @param value Ether value of Safe transaction.
                /// @param data Data payload of Safe transaction.
                /// @param operation Operation type of Safe transaction.
                /// @param safeTxGas Gas that should be used for the Safe transaction.
                /// @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
                /// @param gasPrice Gas price that should be used for the payment calculation.
                /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
                function execTransaction(
                    address to,
                    uint256 value,
                    bytes calldata data,
                    Enum.Operation operation,
                    uint256 safeTxGas,
                    uint256 baseGas,
                    uint256 gasPrice,
                    address gasToken,
                    address payable refundReceiver,
                    bytes memory signatures
                ) public payable virtual returns (bool success) {
                    bytes32 txHash;
                    // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                    {
                        bytes memory txHashData =
                            encodeTransactionData(
                                // Transaction info
                                to,
                                value,
                                data,
                                operation,
                                safeTxGas,
                                // Payment info
                                baseGas,
                                gasPrice,
                                gasToken,
                                refundReceiver,
                                // Signature info
                                nonce
                            );
                        // Increase nonce and execute transaction.
                        nonce++;
                        txHash = keccak256(txHashData);
                        checkSignatures(txHash, txHashData, signatures);
                    }
                    address guard = getGuard();
                    {
                        if (guard != address(0)) {
                            Guard(guard).checkTransaction(
                                // Transaction info
                                to,
                                value,
                                data,
                                operation,
                                safeTxGas,
                                // Payment info
                                baseGas,
                                gasPrice,
                                gasToken,
                                refundReceiver,
                                // Signature info
                                signatures,
                                msg.sender
                            );
                        }
                    }
                    // We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
                    // We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
                    require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010");
                    // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                    {
                        uint256 gasUsed = gasleft();
                        // If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
                        // We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
                        success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
                        gasUsed = gasUsed.sub(gasleft());
                        // If no safeTxGas and no gasPrice was set (e.g. both are 0), then the internal tx is required to be successful
                        // This makes it possible to use `estimateGas` without issues, as it searches for the minimum gas where the tx doesn't revert
                        require(success || safeTxGas != 0 || gasPrice != 0, "GS013");
                        // We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
                        uint256 payment = 0;
                        if (gasPrice > 0) {
                            payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
                        }
                        if (success) emit ExecutionSuccess(txHash, payment);
                        else emit ExecutionFailure(txHash, payment);
                    }
                    {
                        if (guard != address(0)) {
                            Guard(guard).checkAfterExecution(txHash, success);
                        }
                    }
                }
                function handlePayment(
                    uint256 gasUsed,
                    uint256 baseGas,
                    uint256 gasPrice,
                    address gasToken,
                    address payable refundReceiver
                ) private returns (uint256 payment) {
                    // solhint-disable-next-line avoid-tx-origin
                    address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
                    if (gasToken == address(0)) {
                        // For ETH we will only adjust the gas price to not be higher than the actual used gas price
                        payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
                        require(receiver.send(payment), "GS011");
                    } else {
                        payment = gasUsed.add(baseGas).mul(gasPrice);
                        require(transferToken(gasToken, receiver, payment), "GS012");
                    }
                }
                /**
                 * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
                 * @param dataHash Hash of the data (could be either a message hash or transaction hash)
                 * @param data That should be signed (this is passed to an external validator contract)
                 * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
                 */
                function checkSignatures(
                    bytes32 dataHash,
                    bytes memory data,
                    bytes memory signatures
                ) public view {
                    // Load threshold to avoid multiple storage loads
                    uint256 _threshold = threshold;
                    // Check that a threshold is set
                    require(_threshold > 0, "GS001");
                    checkNSignatures(dataHash, data, signatures, _threshold);
                }
                /**
                 * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
                 * @param dataHash Hash of the data (could be either a message hash or transaction hash)
                 * @param data That should be signed (this is passed to an external validator contract)
                 * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
                 * @param requiredSignatures Amount of required valid signatures.
                 */
                function checkNSignatures(
                    bytes32 dataHash,
                    bytes memory data,
                    bytes memory signatures,
                    uint256 requiredSignatures
                ) public view {
                    // Check that the provided signature data is not too short
                    require(signatures.length >= requiredSignatures.mul(65), "GS020");
                    // There cannot be an owner with address 0.
                    address lastOwner = address(0);
                    address currentOwner;
                    uint8 v;
                    bytes32 r;
                    bytes32 s;
                    uint256 i;
                    for (i = 0; i < requiredSignatures; i++) {
                        (v, r, s) = signatureSplit(signatures, i);
                        if (v == 0) {
                            // If v is 0 then it is a contract signature
                            // When handling contract signatures the address of the contract is encoded into r
                            currentOwner = address(uint160(uint256(r)));
                            // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                            // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                            // Here we only check that the pointer is not pointing inside the part that is being processed
                            require(uint256(s) >= requiredSignatures.mul(65), "GS021");
                            // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                            require(uint256(s).add(32) <= signatures.length, "GS022");
                            // Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
                            uint256 contractSignatureLen;
                            // solhint-disable-next-line no-inline-assembly
                            assembly {
                                contractSignatureLen := mload(add(add(signatures, s), 0x20))
                            }
                            require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "GS023");
                            // Check signature
                            bytes memory contractSignature;
                            // solhint-disable-next-line no-inline-assembly
                            assembly {
                                // The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
                                contractSignature := add(add(signatures, s), 0x20)
                            }
                            require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "GS024");
                        } else if (v == 1) {
                            // If v is 1 then it is an approved hash
                            // When handling approved hashes the address of the approver is encoded into r
                            currentOwner = address(uint160(uint256(r)));
                            // Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
                            require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "GS025");
                        } else if (v > 30) {
                            // If v > 30 then default va (27,28) has been adjusted for eth_sign flow
                            // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
                            currentOwner = ecrecover(keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
            32", dataHash)), v - 4, r, s);
                        } else {
                            // Default is the ecrecover flow with the provided data hash
                            // Use ecrecover with the messageHash for EOA signatures
                            currentOwner = ecrecover(dataHash, v, r, s);
                        }
                        require(currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "GS026");
                        lastOwner = currentOwner;
                    }
                }
                /// @dev Allows to estimate a Safe transaction.
                ///      This method is only meant for estimation purpose, therefore the call will always revert and encode the result in the revert data.
                ///      Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
                /// @param to Destination address of Safe transaction.
                /// @param value Ether value of Safe transaction.
                /// @param data Data payload of Safe transaction.
                /// @param operation Operation type of Safe transaction.
                /// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
                /// @notice Deprecated in favor of common/StorageAccessible.sol and will be removed in next version.
                function requiredTxGas(
                    address to,
                    uint256 value,
                    bytes calldata data,
                    Enum.Operation operation
                ) external returns (uint256) {
                    uint256 startGas = gasleft();
                    // We don't provide an error message here, as we use it to return the estimate
                    require(execute(to, value, data, operation, gasleft()));
                    uint256 requiredGas = startGas - gasleft();
                    // Convert response to string and return via error message
                    revert(string(abi.encodePacked(requiredGas)));
                }
                /**
                 * @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
                 * @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
                 */
                function approveHash(bytes32 hashToApprove) external {
                    require(owners[msg.sender] != address(0), "GS030");
                    approvedHashes[msg.sender][hashToApprove] = 1;
                    emit ApproveHash(hashToApprove, msg.sender);
                }
                /// @dev Returns the chain id used by this contract.
                function getChainId() public view returns (uint256) {
                    uint256 id;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        id := chainid()
                    }
                    return id;
                }
                function domainSeparator() public view returns (bytes32) {
                    return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, getChainId(), this));
                }
                /// @dev Returns the bytes that are hashed to be signed by owners.
                /// @param to Destination address.
                /// @param value Ether value.
                /// @param data Data payload.
                /// @param operation Operation type.
                /// @param safeTxGas Gas that should be used for the safe transaction.
                /// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
                /// @param gasPrice Maximum gas price that should be used for this transaction.
                /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                /// @param _nonce Transaction nonce.
                /// @return Transaction hash bytes.
                function encodeTransactionData(
                    address to,
                    uint256 value,
                    bytes calldata data,
                    Enum.Operation operation,
                    uint256 safeTxGas,
                    uint256 baseGas,
                    uint256 gasPrice,
                    address gasToken,
                    address refundReceiver,
                    uint256 _nonce
                ) public view returns (bytes memory) {
                    bytes32 safeTxHash =
                        keccak256(
                            abi.encode(
                                SAFE_TX_TYPEHASH,
                                to,
                                value,
                                keccak256(data),
                                operation,
                                safeTxGas,
                                baseGas,
                                gasPrice,
                                gasToken,
                                refundReceiver,
                                _nonce
                            )
                        );
                    return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator(), safeTxHash);
                }
                /// @dev Returns hash to be signed by owners.
                /// @param to Destination address.
                /// @param value Ether value.
                /// @param data Data payload.
                /// @param operation Operation type.
                /// @param safeTxGas Fas that should be used for the safe transaction.
                /// @param baseGas Gas costs for data used to trigger the safe transaction.
                /// @param gasPrice Maximum gas price that should be used for this transaction.
                /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                /// @param _nonce Transaction nonce.
                /// @return Transaction hash.
                function getTransactionHash(
                    address to,
                    uint256 value,
                    bytes calldata data,
                    Enum.Operation operation,
                    uint256 safeTxGas,
                    uint256 baseGas,
                    uint256 gasPrice,
                    address gasToken,
                    address refundReceiver,
                    uint256 _nonce
                ) public view returns (bytes32) {
                    return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "../common/Enum.sol";
            /// @title Executor - A contract that can execute transactions
            /// @author Richard Meissner - <[email protected]>
            contract Executor {
                function execute(
                    address to,
                    uint256 value,
                    bytes memory data,
                    Enum.Operation operation,
                    uint256 txGas
                ) internal returns (bool success) {
                    if (operation == Enum.Operation.DelegateCall) {
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                        }
                    } else {
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                        }
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "../common/SelfAuthorized.sol";
            /// @title Fallback Manager - A contract that manages fallback calls made to this contract
            /// @author Richard Meissner - <[email protected]>
            contract FallbackManager is SelfAuthorized {
                event ChangedFallbackHandler(address handler);
                // keccak256("fallback_manager.handler.address")
                bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
                function internalSetFallbackHandler(address handler) internal {
                    bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        sstore(slot, handler)
                    }
                }
                /// @dev Allows to add a contract to handle fallback calls.
                ///      Only fallback calls without value and with data will be forwarded.
                ///      This can only be done via a Safe transaction.
                /// @param handler contract to handle fallbacks calls.
                function setFallbackHandler(address handler) public authorized {
                    internalSetFallbackHandler(handler);
                    emit ChangedFallbackHandler(handler);
                }
                // solhint-disable-next-line payable-fallback,no-complex-fallback
                fallback() external {
                    bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let handler := sload(slot)
                        if iszero(handler) {
                            return(0, 0)
                        }
                        calldatacopy(0, 0, calldatasize())
                        // The msg.sender address is shifted to the left by 12 bytes to remove the padding
                        // Then the address without padding is stored right after the calldata
                        mstore(calldatasize(), shl(96, caller()))
                        // Add 20 bytes for the address appended add the end
                        let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
                        returndatacopy(0, 0, returndatasize())
                        if iszero(success) {
                            revert(0, returndatasize())
                        }
                        return(0, returndatasize())
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "../common/Enum.sol";
            import "../common/SelfAuthorized.sol";
            interface Guard {
                function checkTransaction(
                    address to,
                    uint256 value,
                    bytes memory data,
                    Enum.Operation operation,
                    uint256 safeTxGas,
                    uint256 baseGas,
                    uint256 gasPrice,
                    address gasToken,
                    address payable refundReceiver,
                    bytes memory signatures,
                    address msgSender
                ) external;
                function checkAfterExecution(bytes32 txHash, bool success) external;
            }
            /// @title Fallback Manager - A contract that manages fallback calls made to this contract
            /// @author Richard Meissner - <[email protected]>
            contract GuardManager is SelfAuthorized {
                event ChangedGuard(address guard);
                // keccak256("guard_manager.guard.address")
                bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
                /// @dev Set a guard that checks transactions before execution
                /// @param guard The address of the guard to be used or the 0 address to disable the guard
                function setGuard(address guard) external authorized {
                    bytes32 slot = GUARD_STORAGE_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        sstore(slot, guard)
                    }
                    emit ChangedGuard(guard);
                }
                function getGuard() internal view returns (address guard) {
                    bytes32 slot = GUARD_STORAGE_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        guard := sload(slot)
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "../common/Enum.sol";
            import "../common/SelfAuthorized.sol";
            import "./Executor.sol";
            /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
            /// @author Stefan George - <[email protected]>
            /// @author Richard Meissner - <[email protected]>
            contract ModuleManager is SelfAuthorized, Executor {
                event EnabledModule(address module);
                event DisabledModule(address module);
                event ExecutionFromModuleSuccess(address indexed module);
                event ExecutionFromModuleFailure(address indexed module);
                address internal constant SENTINEL_MODULES = address(0x1);
                mapping(address => address) internal modules;
                function setupModules(address to, bytes memory data) internal {
                    require(modules[SENTINEL_MODULES] == address(0), "GS100");
                    modules[SENTINEL_MODULES] = SENTINEL_MODULES;
                    if (to != address(0))
                        // Setup has to complete successfully or transaction fails.
                        require(execute(to, 0, data, Enum.Operation.DelegateCall, gasleft()), "GS000");
                }
                /// @dev Allows to add a module to the whitelist.
                ///      This can only be done via a Safe transaction.
                /// @notice Enables the module `module` for the Safe.
                /// @param module Module to be whitelisted.
                function enableModule(address module) public authorized {
                    // Module address cannot be null or sentinel.
                    require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                    // Module cannot be added twice.
                    require(modules[module] == address(0), "GS102");
                    modules[module] = modules[SENTINEL_MODULES];
                    modules[SENTINEL_MODULES] = module;
                    emit EnabledModule(module);
                }
                /// @dev Allows to remove a module from the whitelist.
                ///      This can only be done via a Safe transaction.
                /// @notice Disables the module `module` for the Safe.
                /// @param prevModule Module that pointed to the module to be removed in the linked list
                /// @param module Module to be removed.
                function disableModule(address prevModule, address module) public authorized {
                    // Validate module address and check that it corresponds to module index.
                    require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                    require(modules[prevModule] == module, "GS103");
                    modules[prevModule] = modules[module];
                    modules[module] = address(0);
                    emit DisabledModule(module);
                }
                /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
                /// @param to Destination address of module transaction.
                /// @param value Ether value of module transaction.
                /// @param data Data payload of module transaction.
                /// @param operation Operation type of module transaction.
                function execTransactionFromModule(
                    address to,
                    uint256 value,
                    bytes memory data,
                    Enum.Operation operation
                ) public virtual returns (bool success) {
                    // Only whitelisted modules are allowed.
                    require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104");
                    // Execute transaction without further confirmations.
                    success = execute(to, value, data, operation, gasleft());
                    if (success) emit ExecutionFromModuleSuccess(msg.sender);
                    else emit ExecutionFromModuleFailure(msg.sender);
                }
                /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
                /// @param to Destination address of module transaction.
                /// @param value Ether value of module transaction.
                /// @param data Data payload of module transaction.
                /// @param operation Operation type of module transaction.
                function execTransactionFromModuleReturnData(
                    address to,
                    uint256 value,
                    bytes memory data,
                    Enum.Operation operation
                ) public returns (bool success, bytes memory returnData) {
                    success = execTransactionFromModule(to, value, data, operation);
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        // Load free memory location
                        let ptr := mload(0x40)
                        // We allocate memory for the return data by setting the free memory location to
                        // current free memory location + data size + 32 bytes for data size value
                        mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                        // Store the size
                        mstore(ptr, returndatasize())
                        // Store the data
                        returndatacopy(add(ptr, 0x20), 0, returndatasize())
                        // Point the return data to the correct memory location
                        returnData := ptr
                    }
                }
                /// @dev Returns if an module is enabled
                /// @return True if the module is enabled
                function isModuleEnabled(address module) public view returns (bool) {
                    return SENTINEL_MODULES != module && modules[module] != address(0);
                }
                /// @dev Returns array of modules.
                /// @param start Start of the page.
                /// @param pageSize Maximum number of modules that should be returned.
                /// @return array Array of modules.
                /// @return next Start of the next page.
                function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next) {
                    // Init array with max page size
                    array = new address[](pageSize);
                    // Populate return array
                    uint256 moduleCount = 0;
                    address currentModule = modules[start];
                    while (currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
                        array[moduleCount] = currentModule;
                        currentModule = modules[currentModule];
                        moduleCount++;
                    }
                    next = currentModule;
                    // Set correct size of returned array
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        mstore(array, moduleCount)
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            import "../common/SelfAuthorized.sol";
            /// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
            /// @author Stefan George - <[email protected]>
            /// @author Richard Meissner - <[email protected]>
            contract OwnerManager is SelfAuthorized {
                event AddedOwner(address owner);
                event RemovedOwner(address owner);
                event ChangedThreshold(uint256 threshold);
                address internal constant SENTINEL_OWNERS = address(0x1);
                mapping(address => address) internal owners;
                uint256 internal ownerCount;
                uint256 internal threshold;
                /// @dev Setup function sets initial storage of contract.
                /// @param _owners List of Safe owners.
                /// @param _threshold Number of required confirmations for a Safe transaction.
                function setupOwners(address[] memory _owners, uint256 _threshold) internal {
                    // Threshold can only be 0 at initialization.
                    // Check ensures that setup function can only be called once.
                    require(threshold == 0, "GS200");
                    // Validate that threshold is smaller than number of added owners.
                    require(_threshold <= _owners.length, "GS201");
                    // There has to be at least one Safe owner.
                    require(_threshold >= 1, "GS202");
                    // Initializing Safe owners.
                    address currentOwner = SENTINEL_OWNERS;
                    for (uint256 i = 0; i < _owners.length; i++) {
                        // Owner address cannot be null.
                        address owner = _owners[i];
                        require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "GS203");
                        // No duplicate owners allowed.
                        require(owners[owner] == address(0), "GS204");
                        owners[currentOwner] = owner;
                        currentOwner = owner;
                    }
                    owners[currentOwner] = SENTINEL_OWNERS;
                    ownerCount = _owners.length;
                    threshold = _threshold;
                }
                /// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
                ///      This can only be done via a Safe transaction.
                /// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
                /// @param owner New owner address.
                /// @param _threshold New threshold.
                function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized {
                    // Owner address cannot be null, the sentinel or the Safe itself.
                    require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "GS203");
                    // No duplicate owners allowed.
                    require(owners[owner] == address(0), "GS204");
                    owners[owner] = owners[SENTINEL_OWNERS];
                    owners[SENTINEL_OWNERS] = owner;
                    ownerCount++;
                    emit AddedOwner(owner);
                    // Change threshold if threshold was changed.
                    if (threshold != _threshold) changeThreshold(_threshold);
                }
                /// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
                ///      This can only be done via a Safe transaction.
                /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
                /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
                /// @param owner Owner address to be removed.
                /// @param _threshold New threshold.
                function removeOwner(
                    address prevOwner,
                    address owner,
                    uint256 _threshold
                ) public authorized {
                    // Only allow to remove an owner, if threshold can still be reached.
                    require(ownerCount - 1 >= _threshold, "GS201");
                    // Validate owner address and check that it corresponds to owner index.
                    require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
                    require(owners[prevOwner] == owner, "GS205");
                    owners[prevOwner] = owners[owner];
                    owners[owner] = address(0);
                    ownerCount--;
                    emit RemovedOwner(owner);
                    // Change threshold if threshold was changed.
                    if (threshold != _threshold) changeThreshold(_threshold);
                }
                /// @dev Allows to swap/replace an owner from the Safe with another address.
                ///      This can only be done via a Safe transaction.
                /// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
                /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
                /// @param oldOwner Owner address to be replaced.
                /// @param newOwner New owner address.
                function swapOwner(
                    address prevOwner,
                    address oldOwner,
                    address newOwner
                ) public authorized {
                    // Owner address cannot be null, the sentinel or the Safe itself.
                    require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "GS203");
                    // No duplicate owners allowed.
                    require(owners[newOwner] == address(0), "GS204");
                    // Validate oldOwner address and check that it corresponds to owner index.
                    require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "GS203");
                    require(owners[prevOwner] == oldOwner, "GS205");
                    owners[newOwner] = owners[oldOwner];
                    owners[prevOwner] = newOwner;
                    owners[oldOwner] = address(0);
                    emit RemovedOwner(oldOwner);
                    emit AddedOwner(newOwner);
                }
                /// @dev Allows to update the number of required confirmations by Safe owners.
                ///      This can only be done via a Safe transaction.
                /// @notice Changes the threshold of the Safe to `_threshold`.
                /// @param _threshold New threshold.
                function changeThreshold(uint256 _threshold) public authorized {
                    // Validate that threshold is smaller than number of owners.
                    require(_threshold <= ownerCount, "GS201");
                    // There has to be at least one Safe owner.
                    require(_threshold >= 1, "GS202");
                    threshold = _threshold;
                    emit ChangedThreshold(threshold);
                }
                function getThreshold() public view returns (uint256) {
                    return threshold;
                }
                function isOwner(address owner) public view returns (bool) {
                    return owner != SENTINEL_OWNERS && owners[owner] != address(0);
                }
                /// @dev Returns array of owners.
                /// @return Array of Safe owners.
                function getOwners() public view returns (address[] memory) {
                    address[] memory array = new address[](ownerCount);
                    // populate return array
                    uint256 index = 0;
                    address currentOwner = owners[SENTINEL_OWNERS];
                    while (currentOwner != SENTINEL_OWNERS) {
                        array[index] = currentOwner;
                        currentOwner = owners[currentOwner];
                        index++;
                    }
                    return array;
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title Enum - Collection of enums
            /// @author Richard Meissner - <[email protected]>
            contract Enum {
                enum Operation {Call, DelegateCall}
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
            /// @author Richard Meissner - <[email protected]>
            contract EtherPaymentFallback {
                event SafeReceived(address indexed sender, uint256 value);
                /// @dev Fallback function accepts Ether transactions.
                receive() external payable {
                    emit SafeReceived(msg.sender, msg.value);
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title SecuredTokenTransfer - Secure token transfer
            /// @author Richard Meissner - <[email protected]>
            contract SecuredTokenTransfer {
                /// @dev Transfers a token and returns if it was a success
                /// @param token Token that should be transferred
                /// @param receiver Receiver to whom the token should be transferred
                /// @param amount The amount of tokens that should be transferred
                function transferToken(
                    address token,
                    address receiver,
                    uint256 amount
                ) internal returns (bool transferred) {
                    // 0xa9059cbb - keccack("transfer(address,uint256)")
                    bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        // We write the return value to scratch space.
                        // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
                        let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                        switch returndatasize()
                            case 0 {
                                transferred := success
                            }
                            case 0x20 {
                                transferred := iszero(or(iszero(success), iszero(mload(0))))
                            }
                            default {
                                transferred := 0
                            }
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title SelfAuthorized - authorizes current contract to perform actions
            /// @author Richard Meissner - <[email protected]>
            contract SelfAuthorized {
                function requireSelfCall() private view {
                    require(msg.sender == address(this), "GS031");
                }
                modifier authorized() {
                    // This is a function call as it minimized the bytecode size
                    requireSelfCall();
                    _;
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
            /// @author Richard Meissner - <[email protected]>
            contract SignatureDecoder {
                /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
                /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
                /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
                /// @param signatures concatenated rsv signatures
                function signatureSplit(bytes memory signatures, uint256 pos)
                    internal
                    pure
                    returns (
                        uint8 v,
                        bytes32 r,
                        bytes32 s
                    )
                {
                    // The signature format is a compact form of:
                    //   {bytes32 r}{bytes32 s}{uint8 v}
                    // Compact means, uint8 is not padded to 32 bytes.
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let signaturePos := mul(0x41, pos)
                        r := mload(add(signatures, add(signaturePos, 0x20)))
                        s := mload(add(signatures, add(signaturePos, 0x40)))
                        // Here we are loading the last 32 bytes, including 31 bytes
                        // of 's'. There is no 'mload8' to do this.
                        //
                        // 'byte' is not working due to the Solidity parser, so lets
                        // use the second best option, 'and'
                        v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title Singleton - Base for singleton contracts (should always be first super contract)
            ///         This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
            /// @author Richard Meissner - <[email protected]>
            contract Singleton {
                // singleton always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
                // It should also always be ensured that the address is stored alone (uses a full word)
                address private singleton;
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
            /// @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
            contract StorageAccessible {
                /**
                 * @dev Reads `length` bytes of storage in the currents contract
                 * @param offset - the offset in the current contract's storage in words to start reading from
                 * @param length - the number of words (32 bytes) of data to read
                 * @return the bytes that were read.
                 */
                function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
                    bytes memory result = new bytes(length * 32);
                    for (uint256 index = 0; index < length; index++) {
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            let word := sload(add(offset, index))
                            mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                        }
                    }
                    return result;
                }
                /**
                 * @dev Performs a delegetecall on a targetContract in the context of self.
                 * Internally reverts execution to avoid side effects (making it static).
                 *
                 * This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
                 * Specifically, the `returndata` after a call to this method will be:
                 * `success:bool || response.length:uint256 || response:bytes`.
                 *
                 * @param targetContract Address of the contract containing the code to execute.
                 * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
                 */
                function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
                        mstore(0x00, success)
                        mstore(0x20, returndatasize())
                        returndatacopy(0x40, 0, returndatasize())
                        revert(0, add(returndatasize(), 0x40))
                    }
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            /**
             * @title GnosisSafeMath
             * @dev Math operations with safety checks that revert on error
             * Renamed from SafeMath to GnosisSafeMath to avoid conflicts
             * TODO: remove once open zeppelin update to solc 0.5.0
             */
            library GnosisSafeMath {
                /**
                 * @dev Multiplies two numbers, reverts on overflow.
                 */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // 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-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    require(c / a == b);
                    return c;
                }
                /**
                 * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                 */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a);
                    uint256 c = a - b;
                    return c;
                }
                /**
                 * @dev Adds two numbers, reverts on overflow.
                 */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a);
                    return c;
                }
                /**
                 * @dev Returns the largest of two numbers.
                 */
                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                    return a >= b ? a : b;
                }
            }
            // SPDX-License-Identifier: LGPL-3.0-only
            pragma solidity >=0.7.0 <0.9.0;
            contract ISignatureValidatorConstants {
                // bytes4(keccak256("isValidSignature(bytes,bytes)")
                bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
            }
            abstract contract ISignatureValidator is ISignatureValidatorConstants {
                /**
                 * @dev Should return whether the signature provided is valid for the provided data
                 * @param _data Arbitrary length data signed on the behalf of address(this)
                 * @param _signature Signature byte array associated with _data
                 *
                 * MUST return the bytes4 magic value 0x20c13b0b when function passes.
                 * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
                 * MUST allow external calls
                 */
                function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
            }